From 77fc4c146f0870ffb09c1afb823ccbe742c5e6ff Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 25 Dec 2021 23:30:44 +0100 Subject: Vendor import of llvm-project main llvmorg-14-init-13186-g0c553cc1af2e. --- llvm/lib/Analysis/AliasAnalysis.cpp | 12 +- llvm/lib/Analysis/Analysis.cpp | 1 + llvm/lib/Analysis/BasicAliasAnalysis.cpp | 3 + llvm/lib/Analysis/CaptureTracking.cpp | 7 +- llvm/lib/Analysis/ConstantFolding.cpp | 21 +- llvm/lib/Analysis/CycleAnalysis.cpp | 77 ++ llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp | 131 +- llvm/lib/Analysis/IVDescriptors.cpp | 2 +- llvm/lib/Analysis/InlineAdvisor.cpp | 11 +- llvm/lib/Analysis/InstructionSimplify.cpp | 112 +- llvm/lib/Analysis/LoopAccessAnalysis.cpp | 21 +- llvm/lib/Analysis/MLInlineAdvisor.cpp | 62 +- llvm/lib/Analysis/MemDerefPrinter.cpp | 8 +- llvm/lib/Analysis/MemoryBuiltins.cpp | 14 +- llvm/lib/Analysis/MemoryLocation.cpp | 81 +- llvm/lib/Analysis/ModelUnderTrainingRunner.cpp | 49 + llvm/lib/Analysis/ModuleSummaryAnalysis.cpp | 18 +- llvm/lib/Analysis/NoInferenceModelRunner.cpp | 33 + llvm/lib/Analysis/ReleaseModeModelRunner.cpp | 90 -- llvm/lib/Analysis/ScalarEvolution.cpp | 34 +- llvm/lib/Analysis/TargetLibraryInfo.cpp | 5 +- llvm/lib/Analysis/TargetTransformInfo.cpp | 15 +- llvm/lib/Analysis/ValueTracking.cpp | 32 +- llvm/lib/AsmParser/LLLexer.cpp | 2 + llvm/lib/AsmParser/LLParser.cpp | 36 +- llvm/lib/BinaryFormat/AMDGPUMetadataVerifier.cpp | 6 +- llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp | 25 +- llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 35 +- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 8 +- llvm/lib/Bitcode/Writer/ValueEnumerator.cpp | 16 +- llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp | 9 +- llvm/lib/CodeGen/Analysis.cpp | 4 +- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 22 +- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 29 +- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h | 2 + llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 25 +- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 10 +- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp | 11 +- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h | 19 +- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 59 +- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h | 3 + llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp | 39 +- llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp | 3 +- llvm/lib/CodeGen/BranchFolding.cpp | 4 +- llvm/lib/CodeGen/CalcSpillWeights.cpp | 22 +- llvm/lib/CodeGen/CodeGen.cpp | 2 + llvm/lib/CodeGen/CodeGenPrepare.cpp | 11 +- llvm/lib/CodeGen/CriticalAntiDepBreaker.cpp | 3 +- llvm/lib/CodeGen/DeadMachineInstructionElim.cpp | 6 +- llvm/lib/CodeGen/EarlyIfConversion.cpp | 20 +- llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 36 +- llvm/lib/CodeGen/GlobalISel/Combiner.cpp | 2 +- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp | 4 +- llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 9 +- llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp | 8 +- llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 1119 ++++++++--------- llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp | 5 +- llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 48 +- llvm/lib/CodeGen/GlobalISel/Utils.cpp | 39 +- llvm/lib/CodeGen/ImplicitNullChecks.cpp | 2 +- llvm/lib/CodeGen/InlineSpiller.cpp | 4 +- llvm/lib/CodeGen/InterferenceCache.cpp | 4 +- .../CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp | 4 +- .../CodeGen/LiveDebugValues/VarLocBasedImpl.cpp | 16 +- llvm/lib/CodeGen/LiveDebugVariables.cpp | 11 +- llvm/lib/CodeGen/LiveDebugVariables.h | 5 + llvm/lib/CodeGen/LiveRangeEdit.cpp | 16 + llvm/lib/CodeGen/LiveVariables.cpp | 14 +- llvm/lib/CodeGen/LocalStackSlotAllocation.cpp | 6 +- llvm/lib/CodeGen/MIRParser/MIRParser.cpp | 18 + llvm/lib/CodeGen/MIRPrinter.cpp | 2 + llvm/lib/CodeGen/MachineBasicBlock.cpp | 31 +- llvm/lib/CodeGen/MachineBlockPlacement.cpp | 161 ++- llvm/lib/CodeGen/MachineCombiner.cpp | 4 +- llvm/lib/CodeGen/MachineCopyPropagation.cpp | 28 +- llvm/lib/CodeGen/MachineCycleAnalysis.cpp | 113 ++ llvm/lib/CodeGen/MachineFunction.cpp | 32 +- llvm/lib/CodeGen/MachineInstr.cpp | 32 +- llvm/lib/CodeGen/MachinePipeliner.cpp | 73 +- llvm/lib/CodeGen/MachineSSAContext.cpp | 52 + llvm/lib/CodeGen/MachineSSAUpdater.cpp | 27 +- llvm/lib/CodeGen/MachineScheduler.cpp | 21 +- llvm/lib/CodeGen/MachineTraceMetrics.cpp | 25 +- llvm/lib/CodeGen/MachineVerifier.cpp | 82 +- llvm/lib/CodeGen/PHIElimination.cpp | 4 +- llvm/lib/CodeGen/PostRASchedulerList.cpp | 17 +- llvm/lib/CodeGen/PrologEpilogInserter.cpp | 14 +- llvm/lib/CodeGen/RDFGraph.cpp | 4 +- llvm/lib/CodeGen/RegAllocEvictionAdvisor.cpp | 121 ++ llvm/lib/CodeGen/RegAllocEvictionAdvisor.h | 210 ++++ llvm/lib/CodeGen/RegAllocGreedy.cpp | 211 +--- llvm/lib/CodeGen/RegAllocPBQP.cpp | 4 +- llvm/lib/CodeGen/RegAllocScore.cpp | 124 ++ llvm/lib/CodeGen/RegAllocScore.h | 80 ++ llvm/lib/CodeGen/RegisterClassInfo.cpp | 3 +- llvm/lib/CodeGen/RegisterCoalescer.cpp | 8 +- llvm/lib/CodeGen/RemoveRedundantDebugValues.cpp | 17 +- llvm/lib/CodeGen/SafeStack.cpp | 18 +- llvm/lib/CodeGen/SafeStackLayout.cpp | 7 +- llvm/lib/CodeGen/SafeStackLayout.h | 12 +- llvm/lib/CodeGen/ScheduleDAG.cpp | 8 +- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 655 ++++++---- llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 8 +- .../CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp | 16 +- llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp | 10 +- .../lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp | 99 +- .../CodeGen/SelectionDAG/ResourcePriorityQueue.cpp | 7 +- .../CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp | 30 +- llvm/lib/CodeGen/SelectionDAG/ScheduleDAGVLIW.cpp | 8 +- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 61 +- .../CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 82 +- .../lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h | 5 +- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 20 +- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 59 +- llvm/lib/CodeGen/ShadowStackGCLowering.cpp | 14 +- llvm/lib/CodeGen/StackMapLivenessAnalysis.cpp | 10 +- llvm/lib/CodeGen/StackProtector.cpp | 21 +- llvm/lib/CodeGen/StackSlotColoring.cpp | 10 +- llvm/lib/CodeGen/TailDuplicator.cpp | 42 +- llvm/lib/CodeGen/TargetInstrInfo.cpp | 15 +- llvm/lib/CodeGen/TargetLoweringBase.cpp | 2 +- llvm/lib/CodeGen/TargetRegisterInfo.cpp | 4 +- llvm/lib/CodeGen/UnreachableBlockElim.cpp | 21 +- llvm/lib/CodeGen/VLIWMachineScheduler.cpp | 1009 ++++++++++++++++ llvm/lib/CodeGen/ValueTypes.cpp | 4 +- llvm/lib/CodeGen/WinEHPrepare.cpp | 15 +- llvm/lib/CodeGen/XRayInstrumentation.cpp | 1 + llvm/lib/DWARFLinker/DWARFLinker.cpp | 46 +- llvm/lib/DWARFLinker/DWARFStreamer.cpp | 4 +- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp | 2 +- llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp | 15 +- llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp | 11 +- llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp | 6 +- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 4 +- llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp | 4 +- llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp | 47 +- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 12 +- llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp | 80 +- llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp | 4 +- llvm/lib/DebugInfo/MSF/MSFBuilder.cpp | 26 +- llvm/lib/DebugInfo/MSF/MSFError.cpp | 8 +- llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp | 2 +- llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp | 4 +- llvm/lib/DebugInfo/Symbolize/Symbolize.cpp | 10 +- llvm/lib/Debuginfod/Debuginfod.cpp | 183 +++ llvm/lib/Debuginfod/HTTPClient.cpp | 216 ++++ llvm/lib/Demangle/DLangDemangle.cpp | 66 ++ llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp | 6 +- llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp | 4 +- llvm/lib/ExecutionEngine/MCJIT/MCJIT.h | 10 +- .../ExecutionEngine/Orc/CompileOnDemandLayer.cpp | 11 +- llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp | 3 +- llvm/lib/ExecutionEngine/Orc/Core.cpp | 30 +- .../ExecutionEngine/Orc/DebuggerSupportPlugin.cpp | 18 +- llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp | 13 +- llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp | 44 +- llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp | 4 +- llvm/lib/ExecutionEngine/Orc/Layer.cpp | 57 +- llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp | 6 +- llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp | 12 +- llvm/lib/ExecutionEngine/Orc/Mangling.cpp | 188 --- .../ExecutionEngine/Orc/ObjectFileInterface.cpp | 205 ++++ .../lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp | 29 +- llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp | 4 +- .../ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp | 22 +- llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp | 72 +- llvm/lib/IR/AsmWriter.cpp | 46 +- llvm/lib/IR/AttributeImpl.h | 3 +- llvm/lib/IR/Attributes.cpp | 69 +- llvm/lib/IR/AutoUpgrade.cpp | 134 ++- llvm/lib/IR/BasicBlock.cpp | 4 +- llvm/lib/IR/ConstantFold.cpp | 51 +- llvm/lib/IR/Constants.cpp | 57 +- llvm/lib/IR/Core.cpp | 25 +- llvm/lib/IR/DIBuilder.cpp | 8 +- llvm/lib/IR/DataLayout.cpp | 129 +- llvm/lib/IR/Function.cpp | 17 +- llvm/lib/IR/Globals.cpp | 4 +- llvm/lib/IR/InlineAsm.cpp | 6 +- llvm/lib/IR/Instruction.cpp | 11 +- llvm/lib/IR/Instructions.cpp | 48 +- llvm/lib/IR/IntrinsicInst.cpp | 14 +- llvm/lib/IR/LLVMContextImpl.h | 7 +- llvm/lib/IR/LegacyPassManager.cpp | 12 +- llvm/lib/IR/Module.cpp | 18 +- llvm/lib/IR/ModuleSummaryIndex.cpp | 16 +- llvm/lib/IR/Operator.cpp | 5 +- llvm/lib/IR/SSAContext.cpp | 47 + llvm/lib/IR/Value.cpp | 2 +- llvm/lib/IR/Verifier.cpp | 87 +- llvm/lib/LTO/LTO.cpp | 4 +- llvm/lib/LTO/LTOBackend.cpp | 3 +- llvm/lib/LTO/LTOCodeGenerator.cpp | 5 +- llvm/lib/LTO/ThinLTOCodeGenerator.cpp | 6 +- llvm/lib/LineEditor/LineEditor.cpp | 5 +- llvm/lib/Linker/IRMover.cpp | 4 +- llvm/lib/MC/MCAsmStreamer.cpp | 20 + llvm/lib/MC/MCAssembler.cpp | 3 + llvm/lib/MC/MCInstrAnalysis.cpp | 2 +- llvm/lib/MC/MCMachOStreamer.cpp | 15 +- llvm/lib/MC/MCNullStreamer.cpp | 3 + llvm/lib/MC/MCObjectStreamer.cpp | 25 + llvm/lib/MC/MCParser/AsmParser.cpp | 67 +- llvm/lib/MC/MCPseudoProbe.cpp | 4 +- llvm/lib/MC/MCStreamer.cpp | 72 +- llvm/lib/MC/MCWin64EH.cpp | 6 +- llvm/lib/MC/MachObjectWriter.cpp | 88 +- llvm/lib/MC/TargetRegistry.cpp | 8 +- llvm/lib/Object/ArchiveWriter.cpp | 2 +- llvm/lib/Object/ELF.cpp | 2 + llvm/lib/Object/MachOObjectFile.cpp | 46 + llvm/lib/Object/MachOUniversalWriter.cpp | 1 - llvm/lib/ObjectYAML/COFFEmitter.cpp | 12 +- llvm/lib/ObjectYAML/ELFYAML.cpp | 48 +- llvm/lib/ObjectYAML/XCOFFEmitter.cpp | 10 +- llvm/lib/ObjectYAML/YAML.cpp | 5 +- llvm/lib/Option/OptTable.cpp | 10 +- llvm/lib/Passes/PassBuilder.cpp | 2 + llvm/lib/Passes/PassBuilderPipelines.cpp | 80 +- llvm/lib/Passes/PassRegistry.def | 4 + llvm/lib/Passes/StandardInstrumentations.cpp | 140 +-- llvm/lib/ProfileData/InstrProf.cpp | 25 +- llvm/lib/ProfileData/InstrProfCorrelator.cpp | 264 +++++ llvm/lib/ProfileData/InstrProfReader.cpp | 131 +- llvm/lib/ProfileData/InstrProfWriter.cpp | 1 + llvm/lib/ProfileData/ProfileSummaryBuilder.cpp | 2 +- llvm/lib/ProfileData/SampleProf.cpp | 121 +- llvm/lib/ProfileData/SampleProfReader.cpp | 115 +- llvm/lib/ProfileData/SampleProfWriter.cpp | 75 +- llvm/lib/Support/AArch64TargetParser.cpp | 2 +- llvm/lib/Support/Caching.cpp | 13 +- llvm/lib/Support/CommandLine.cpp | 33 +- llvm/lib/Support/Compression.cpp | 8 +- llvm/lib/Support/ConvertUTFWrapper.cpp | 4 +- llvm/lib/Support/DAGDeltaAlgorithm.cpp | 68 +- llvm/lib/Support/DeltaAlgorithm.cpp | 5 +- llvm/lib/Support/HTTPClient.cpp | 97 -- llvm/lib/Support/KnownBits.cpp | 18 +- llvm/lib/Support/MemoryBuffer.cpp | 9 +- llvm/lib/Support/NativeFormatting.cpp | 2 +- llvm/lib/Support/Path.cpp | 4 +- llvm/lib/Support/RISCVISAInfo.cpp | 259 ++-- llvm/lib/Support/ScopedPrinter.cpp | 10 + llvm/lib/Support/Signals.cpp | 6 +- llvm/lib/Support/SourceMgr.cpp | 3 +- llvm/lib/Support/Statistic.cpp | 17 +- llvm/lib/Support/TargetParser.cpp | 15 + llvm/lib/Support/ThreadPool.cpp | 24 +- llvm/lib/Support/Triple.cpp | 126 +- llvm/lib/Support/Unix/Path.inc | 13 - llvm/lib/Support/VirtualFileSystem.cpp | 6 + llvm/lib/Support/YAMLParser.cpp | 4 +- llvm/lib/TableGen/StringMatcher.cpp | 13 +- llvm/lib/Target/AArch64/AArch64.td | 3 + llvm/lib/Target/AArch64/AArch64A53Fix835769.cpp | 8 +- .../Target/AArch64/AArch64AdvSIMDScalarPass.cpp | 4 +- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 14 + llvm/lib/Target/AArch64/AArch64Combine.td | 10 +- llvm/lib/Target/AArch64/AArch64ExpandImm.cpp | 7 +- llvm/lib/Target/AArch64/AArch64FalkorHWPFFix.cpp | 8 +- llvm/lib/Target/AArch64/AArch64FrameLowering.cpp | 11 + llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 222 +++- llvm/lib/Target/AArch64/AArch64ISelLowering.h | 2 + llvm/lib/Target/AArch64/AArch64InstrFormats.td | 64 +- llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 2 + llvm/lib/Target/AArch64/AArch64InstrInfo.td | 95 ++ llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td | 44 +- llvm/lib/Target/AArch64/AArch64StackTagging.cpp | 17 +- llvm/lib/Target/AArch64/AArch64Subtarget.cpp | 4 +- llvm/lib/Target/AArch64/AArch64Subtarget.h | 7 +- llvm/lib/Target/AArch64/AArch64TargetMachine.cpp | 15 +- .../Target/AArch64/AArch64TargetTransformInfo.cpp | 74 +- .../Target/AArch64/AArch64TargetTransformInfo.h | 2 + .../Target/AArch64/AsmParser/AArch64AsmParser.cpp | 7 +- .../Target/AArch64/GISel/AArch64LegalizerInfo.cpp | 5 + .../AArch64/GISel/AArch64PostLegalizerCombiner.cpp | 38 + .../AArch64/GISel/AArch64RegisterBankInfo.cpp | 4 + .../AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp | 4 +- llvm/lib/Target/AArch64/SVEInstrFormats.td | 100 +- llvm/lib/Target/AArch64/SVEIntrinsicOpts.cpp | 14 +- llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.cpp | 11 +- llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp | 26 +- llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp | 33 +- llvm/lib/Target/AMDGPU/AMDGPUCombine.td | 28 +- llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp | 1 - llvm/lib/Target/AMDGPU/AMDGPUGISel.td | 2 + .../Target/AMDGPU/AMDGPUHSAMetadataStreamer.cpp | 26 +- llvm/lib/Target/AMDGPU/AMDGPUHSAMetadataStreamer.h | 12 +- .../Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp | 9 + llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp | 106 +- .../lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp | 116 +- .../Target/AMDGPU/AMDGPUMachineCFGStructurizer.cpp | 8 +- llvm/lib/Target/AMDGPU/AMDGPUPerfHintAnalysis.cpp | 42 +- llvm/lib/Target/AMDGPU/AMDGPUPromoteAlloca.cpp | 2 +- llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp | 192 ++- llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp | 33 +- .../AMDGPU/AMDGPUReplaceLDSUseWithPointer.cpp | 210 +++- llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp | 21 +- llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp | 8 - llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h | 1 - .../Target/AMDGPU/AMDGPUTargetTransformInfo.cpp | 85 -- llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp | 23 +- .../Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp | 8 +- llvm/lib/Target/AMDGPU/BUFInstructions.td | 8 +- llvm/lib/Target/AMDGPU/FLATInstructions.td | 10 +- .../Target/AMDGPU/MCA/AMDGPUCustomBehaviour.cpp | 3 +- .../lib/Target/AMDGPU/R600ControlFlowFinalizer.cpp | 21 +- llvm/lib/Target/AMDGPU/R600InstrInfo.cpp | 48 +- llvm/lib/Target/AMDGPU/R600MachineScheduler.cpp | 6 +- .../AMDGPU/R600OpenCLImageTypeLoweringPass.cpp | 4 +- .../Target/AMDGPU/R600OptimizeVectorRegisters.cpp | 42 +- llvm/lib/Target/AMDGPU/R600Packetizer.cpp | 4 +- llvm/lib/Target/AMDGPU/R600RegisterInfo.cpp | 6 +- llvm/lib/Target/AMDGPU/SIFoldOperands.cpp | 6 +- llvm/lib/Target/AMDGPU/SIFrameLowering.cpp | 12 +- llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 73 +- llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp | 160 ++- llvm/lib/Target/AMDGPU/SIInstrInfo.cpp | 153 ++- llvm/lib/Target/AMDGPU/SIInstrInfo.td | 8 +- llvm/lib/Target/AMDGPU/SIInstructions.td | 116 +- llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp | 24 +- llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h | 7 + llvm/lib/Target/AMDGPU/SIMachineScheduler.cpp | 53 +- llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp | 59 +- llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp | 11 +- llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp | 9 +- llvm/lib/Target/AMDGPU/SMInstructions.td | 21 +- llvm/lib/Target/AMDGPU/SOPInstructions.td | 106 +- llvm/lib/Target/AMDGPU/Utils/AMDGPULDSUtils.cpp | 231 +--- llvm/lib/Target/AMDGPU/Utils/AMDGPULDSUtils.h | 31 - llvm/lib/Target/AMDGPU/VOPInstructions.td | 12 + llvm/lib/Target/ARM/A15SDOptimizer.cpp | 16 +- llvm/lib/Target/ARM/ARM.td | 5 + llvm/lib/Target/ARM/ARMAsmPrinter.cpp | 36 +- llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp | 217 +++- llvm/lib/Target/ARM/ARMBaseInstrInfo.h | 27 +- llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp | 4 + llvm/lib/Target/ARM/ARMBranchTargets.cpp | 5 +- llvm/lib/Target/ARM/ARMCallingConv.cpp | 7 +- llvm/lib/Target/ARM/ARMConstantIslandPass.cpp | 48 +- llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp | 24 + llvm/lib/Target/ARM/ARMFrameLowering.cpp | 94 +- llvm/lib/Target/ARM/ARMISelLowering.cpp | 221 +++- llvm/lib/Target/ARM/ARMISelLowering.h | 1 + llvm/lib/Target/ARM/ARMInstrMVE.td | 116 +- llvm/lib/Target/ARM/ARMInstrThumb2.td | 7 + llvm/lib/Target/ARM/ARMInstrVFP.td | 3 + llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp | 5 +- llvm/lib/Target/ARM/ARMLowOverheadLoops.cpp | 16 +- llvm/lib/Target/ARM/ARMMachineFunctionInfo.h | 2 +- llvm/lib/Target/ARM/ARMRegisterInfo.td | 4 +- llvm/lib/Target/ARM/ARMSubtarget.h | 9 + llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 63 +- .../lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp | 67 +- .../lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp | 5 +- .../Target/ARM/MVETPAndVPTOptimisationsPass.cpp | 2 +- llvm/lib/Target/ARM/MVETailPredication.cpp | 10 +- llvm/lib/Target/ARM/Thumb1FrameLowering.cpp | 9 +- llvm/lib/Target/AVR/AVRFrameLowering.cpp | 4 +- llvm/lib/Target/AVR/AVRInstrInfo.cpp | 2 - llvm/lib/Target/BPF/BPFPreserveDIType.cpp | 9 +- llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp | 91 +- llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp | 13 + llvm/lib/Target/CSKY/CSKYAsmPrinter.h | 2 + llvm/lib/Target/CSKY/CSKYCallingConv.td | 2 +- llvm/lib/Target/CSKY/CSKYFrameLowering.cpp | 2 +- llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp | 89 +- llvm/lib/Target/CSKY/CSKYISelLowering.cpp | 40 + llvm/lib/Target/CSKY/CSKYInstrFormats16Instr.td | 15 +- llvm/lib/Target/CSKY/CSKYInstrInfo.cpp | 288 +++++ llvm/lib/Target/CSKY/CSKYInstrInfo.h | 25 + llvm/lib/Target/CSKY/CSKYInstrInfo.td | 241 +++- llvm/lib/Target/CSKY/CSKYInstrInfo16Instr.td | 165 ++- llvm/lib/Target/CSKY/CSKYMCInstLower.cpp | 2 +- llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp | 181 ++- llvm/lib/Target/CSKY/CSKYRegisterInfo.h | 12 + llvm/lib/Target/CSKY/CSKYRegisterInfo.td | 5 + llvm/lib/Target/Hexagon/Hexagon.td | 55 +- llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp | 61 + llvm/lib/Target/Hexagon/HexagonAsmPrinter.h | 16 +- llvm/lib/Target/Hexagon/HexagonBitSimplify.cpp | 22 +- llvm/lib/Target/Hexagon/HexagonCommonGEP.cpp | 12 +- llvm/lib/Target/Hexagon/HexagonDepArch.h | 34 +- llvm/lib/Target/Hexagon/HexagonDepArch.td | 2 + llvm/lib/Target/Hexagon/HexagonDepDecoders.inc | 1 + llvm/lib/Target/Hexagon/HexagonDepIICHVX.td | 1020 +++++++++++++++- llvm/lib/Target/Hexagon/HexagonDepIICScalar.td | 768 ++++++++++++ llvm/lib/Target/Hexagon/HexagonDepInstrFormats.td | 14 + llvm/lib/Target/Hexagon/HexagonDepInstrInfo.td | 1253 ++++++++++++++++++-- llvm/lib/Target/Hexagon/HexagonDepMapAsm2Intrin.td | 293 ++++- llvm/lib/Target/Hexagon/HexagonDepMappings.td | 1 - llvm/lib/Target/Hexagon/HexagonGenInsert.cpp | 4 +- .../lib/Target/Hexagon/HexagonHazardRecognizer.cpp | 4 +- llvm/lib/Target/Hexagon/HexagonInstrFormats.td | 7 +- llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp | 9 + llvm/lib/Target/Hexagon/HexagonInstrInfo.h | 2 + llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp | 13 + .../lib/Target/Hexagon/HexagonMachineScheduler.cpp | 964 +-------------- llvm/lib/Target/Hexagon/HexagonMachineScheduler.h | 253 +--- llvm/lib/Target/Hexagon/HexagonPseudo.td | 11 + llvm/lib/Target/Hexagon/HexagonSchedule.td | 1 + llvm/lib/Target/Hexagon/HexagonScheduleV69.td | 40 + llvm/lib/Target/Hexagon/HexagonSubtarget.cpp | 72 +- llvm/lib/Target/Hexagon/HexagonSubtarget.h | 27 +- llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp | 5 +- llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp | 9 +- llvm/lib/Target/Hexagon/HexagonVectorCombine.cpp | 2 +- .../Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h | 5 +- .../Hexagon/MCTargetDesc/HexagonMCChecker.cpp | 38 +- .../Target/Hexagon/MCTargetDesc/HexagonMCChecker.h | 1 + .../Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp | 18 +- .../Hexagon/MCTargetDesc/HexagonMCInstrInfo.h | 4 +- .../Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp | 32 +- llvm/lib/Target/M68k/M68kInstrControl.td | 16 +- llvm/lib/Target/MSP430/MSP430FrameLowering.cpp | 4 +- llvm/lib/Target/Mips/Mips16HardFloat.cpp | 6 +- llvm/lib/Target/Mips/MipsBranchExpansion.cpp | 52 +- llvm/lib/Target/Mips/MipsISelLowering.cpp | 2 +- llvm/lib/Target/Mips/MipsInstrInfo.cpp | 49 + llvm/lib/Target/Mips/MipsInstrInfo.h | 7 + llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp | 12 +- llvm/lib/Target/NVPTX/NVPTXPeephole.cpp | 6 +- llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp | 12 +- .../PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp | 29 + llvm/lib/Target/PowerPC/PPC.td | 4 + llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 1 - llvm/lib/Target/PowerPC/PPCBack2BackFusion.def | 1042 ++++++++++++++++ llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 14 +- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 56 +- llvm/lib/Target/PowerPC/PPCInstrInfo.h | 4 +- llvm/lib/Target/PowerPC/PPCInstrInfo.td | 1 + llvm/lib/Target/PowerPC/PPCInstrVSX.td | 17 + llvm/lib/Target/PowerPC/PPCLoopInstrFormPrep.cpp | 6 +- llvm/lib/Target/PowerPC/PPCMacroFusion.def | 2 + llvm/lib/Target/PowerPC/PPCSubtarget.cpp | 1 + llvm/lib/Target/PowerPC/PPCSubtarget.h | 2 + llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp | 103 +- llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h | 16 +- llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 124 +- .../Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp | 5 + llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h | 10 + .../Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp | 4 +- llvm/lib/Target/RISCV/RISCV.td | 8 - llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 71 +- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 277 +++-- llvm/lib/Target/RISCV/RISCVISelLowering.h | 12 +- llvm/lib/Target/RISCV/RISCVInstrFormats.td | 70 +- llvm/lib/Target/RISCV/RISCVInstrFormatsV.td | 32 - llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 5 +- llvm/lib/Target/RISCV/RISCVInstrInfo.h | 5 + llvm/lib/Target/RISCV/RISCVInstrInfo.td | 52 +- llvm/lib/Target/RISCV/RISCVInstrInfoD.td | 237 ++-- llvm/lib/Target/RISCV/RISCVInstrInfoF.td | 295 ++--- llvm/lib/Target/RISCV/RISCVInstrInfoM.td | 13 - llvm/lib/Target/RISCV/RISCVInstrInfoV.td | 72 +- llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td | 1229 +++++++++++-------- llvm/lib/Target/RISCV/RISCVInstrInfoZb.td | 65 +- llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td | 254 ++-- llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp | 1 - llvm/lib/Target/RISCV/RISCVRegisterInfo.td | 8 +- llvm/lib/Target/RISCV/RISCVSchedRocket.td | 3 +- llvm/lib/Target/RISCV/RISCVSchedSiFive7.td | 2 +- llvm/lib/Target/RISCV/RISCVSubtarget.h | 2 - llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp | 91 ++ llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h | 11 +- .../SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp | 32 +- .../SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp | 10 +- llvm/lib/Target/SystemZ/SystemZCallingConv.td | 1 + llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp | 180 ++- llvm/lib/Target/SystemZ/SystemZFrameLowering.h | 9 + llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 165 ++- llvm/lib/Target/SystemZ/SystemZISelLowering.h | 6 +- llvm/lib/Target/SystemZ/SystemZInstrFormats.td | 10 + llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 6 + llvm/lib/Target/SystemZ/SystemZOperators.td | 6 + .../lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp | 57 +- llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp | 35 + llvm/lib/Target/VE/MCTargetDesc/VEAsmBackend.cpp | 3 + .../Target/VE/MCTargetDesc/VEELFObjectWriter.cpp | 47 +- llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h | 3 + .../lib/Target/VE/MCTargetDesc/VEMCCodeEmitter.cpp | 6 +- llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp | 11 +- llvm/lib/Target/VE/VEISelLowering.cpp | 2 +- llvm/lib/Target/VE/VVPInstrInfo.td | 35 + llvm/lib/Target/VE/VVPInstrPatternsVec.td | 185 ++- llvm/lib/Target/VE/VVPNodes.def | 32 +- .../WebAssembly/AsmParser/WebAssemblyAsmParser.cpp | 12 - .../AsmParser/WebAssemblyAsmTypeCheck.cpp | 13 +- .../AsmParser/WebAssemblyAsmTypeCheck.h | 2 +- .../Disassembler/WebAssemblyDisassembler.cpp | 22 - .../MCTargetDesc/WebAssemblyInstPrinter.cpp | 23 - .../MCTargetDesc/WebAssemblyInstPrinter.h | 2 - .../MCTargetDesc/WebAssemblyMCAsmInfo.cpp | 9 + .../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 3 - .../MCTargetDesc/WebAssemblyMCTargetDesc.h | 2 - .../WebAssembly/Utils/WebAssemblyTypeUtilities.cpp | 7 - .../WebAssembly/Utils/WebAssemblyTypeUtilities.h | 8 - .../WebAssembly/Utils/WebAssemblyUtilities.cpp | 25 + .../WebAssembly/Utils/WebAssemblyUtilities.h | 7 + .../Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 14 +- .../Target/WebAssembly/WebAssemblyCFGStackify.cpp | 2 +- llvm/lib/Target/WebAssembly/WebAssemblyISD.def | 1 + .../Target/WebAssembly/WebAssemblyISelLowering.cpp | 115 +- .../lib/Target/WebAssembly/WebAssemblyInstrInfo.td | 5 - llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td | 19 +- .../lib/Target/WebAssembly/WebAssemblyInstrSIMD.td | 8 + .../Target/WebAssembly/WebAssemblyInstrTable.td | 16 +- .../WebAssemblyLowerEmscriptenEHSjLj.cpp | 13 +- .../Target/WebAssembly/WebAssemblyMCInstLower.cpp | 24 +- .../WebAssembly/WebAssemblyTargetMachine.cpp | 42 +- llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp | 34 +- llvm/lib/Target/X86/AsmParser/X86Operand.h | 6 + .../Target/X86/MCTargetDesc/X86InstComments.cpp | 24 +- .../X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp | 2 +- llvm/lib/Target/X86/X86AsmPrinter.cpp | 2 - llvm/lib/Target/X86/X86AsmPrinter.h | 19 +- llvm/lib/Target/X86/X86CmovConversion.cpp | 2 +- llvm/lib/Target/X86/X86ExpandPseudo.cpp | 26 +- llvm/lib/Target/X86/X86FastTileConfig.cpp | 6 +- llvm/lib/Target/X86/X86FixupBWInsts.cpp | 10 +- llvm/lib/Target/X86/X86FloatingPoint.cpp | 2 +- llvm/lib/Target/X86/X86FrameLowering.cpp | 23 +- llvm/lib/Target/X86/X86ISelLowering.cpp | 485 +++++--- llvm/lib/Target/X86/X86ISelLowering.h | 10 + llvm/lib/Target/X86/X86IndirectBranchTracking.cpp | 4 +- llvm/lib/Target/X86/X86InstrAVX512.td | 138 +-- llvm/lib/Target/X86/X86InstrCompiler.td | 6 +- llvm/lib/Target/X86/X86InstrFoldTables.cpp | 106 +- llvm/lib/Target/X86/X86InstrInfo.cpp | 107 +- llvm/lib/Target/X86/X86InstrInfo.h | 3 +- llvm/lib/Target/X86/X86InstrMMX.td | 40 +- llvm/lib/Target/X86/X86MCInstLower.cpp | 246 +--- llvm/lib/Target/X86/X86RegisterInfo.td | 10 +- llvm/lib/Target/X86/X86SchedBroadwell.td | 26 +- llvm/lib/Target/X86/X86SchedHaswell.td | 32 +- llvm/lib/Target/X86/X86SchedIceLake.td | 167 ++- llvm/lib/Target/X86/X86SchedSandyBridge.td | 4 +- llvm/lib/Target/X86/X86SchedSkylakeClient.td | 88 +- llvm/lib/Target/X86/X86SchedSkylakeServer.td | 98 +- llvm/lib/Target/X86/X86ScheduleAtom.td | 72 +- llvm/lib/Target/X86/X86ScheduleBdVer2.td | 36 +- llvm/lib/Target/X86/X86ScheduleBtVer2.td | 24 +- llvm/lib/Target/X86/X86ScheduleSLM.td | 8 +- llvm/lib/Target/X86/X86ScheduleZnver1.td | 18 +- llvm/lib/Target/X86/X86ScheduleZnver2.td | 18 +- llvm/lib/Target/X86/X86ScheduleZnver3.td | 14 +- llvm/lib/Target/X86/X86Subtarget.h | 3 +- llvm/lib/Target/X86/X86TargetMachine.cpp | 12 + llvm/lib/Target/X86/X86TargetTransformInfo.cpp | 91 +- llvm/lib/Target/X86/X86TargetTransformInfo.h | 5 +- .../AggressiveInstCombine/TruncInstCombine.cpp | 6 +- llvm/lib/Transforms/CFGuard/CFGuard.cpp | 8 +- llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 33 +- llvm/lib/Transforms/Coroutines/CoroSplit.cpp | 41 +- llvm/lib/Transforms/Coroutines/Coroutines.cpp | 1 - llvm/lib/Transforms/IPO/ArgumentPromotion.cpp | 10 +- llvm/lib/Transforms/IPO/Attributor.cpp | 6 +- llvm/lib/Transforms/IPO/AttributorAttributes.cpp | 38 +- llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 208 ++-- llvm/lib/Transforms/IPO/FunctionSpecialization.cpp | 317 ++--- llvm/lib/Transforms/IPO/GlobalOpt.cpp | 11 +- llvm/lib/Transforms/IPO/HotColdSplitting.cpp | 2 +- llvm/lib/Transforms/IPO/Inliner.cpp | 2 + llvm/lib/Transforms/IPO/LowerTypeTests.cpp | 7 +- llvm/lib/Transforms/IPO/OpenMPOpt.cpp | 6 + llvm/lib/Transforms/IPO/SampleContextTracker.cpp | 21 +- llvm/lib/Transforms/IPO/SampleProfile.cpp | 174 +-- llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp | 3 +- llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp | 104 +- .../Transforms/InstCombine/InstCombineAndOrXor.cpp | 58 + .../Transforms/InstCombine/InstCombineCalls.cpp | 6 + .../Transforms/InstCombine/InstCombineCasts.cpp | 44 +- .../Transforms/InstCombine/InstCombineInternal.h | 1 + .../InstCombine/InstCombineLoadStoreAlloca.cpp | 20 +- .../InstCombine/InstCombineMulDivRem.cpp | 18 + llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp | 7 +- .../Transforms/InstCombine/InstCombineSelect.cpp | 7 +- .../InstCombine/InstCombineSimplifyDemanded.cpp | 6 - .../InstCombine/InstCombineVectorOps.cpp | 165 +-- .../InstCombine/InstructionCombining.cpp | 39 +- .../Instrumentation/DataFlowSanitizer.cpp | 25 +- .../Transforms/Instrumentation/InstrProfiling.cpp | 61 + .../Transforms/Instrumentation/MemorySanitizer.cpp | 13 +- .../Instrumentation/PGOInstrumentation.cpp | 25 +- llvm/lib/Transforms/Scalar/ConstantHoisting.cpp | 3 +- llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp | 58 +- .../lib/Transforms/Scalar/DeadStoreElimination.cpp | 187 +-- llvm/lib/Transforms/Scalar/EarlyCSE.cpp | 12 +- llvm/lib/Transforms/Scalar/FlattenCFGPass.cpp | 49 +- llvm/lib/Transforms/Scalar/LICM.cpp | 44 - llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp | 4 +- llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp | 28 +- llvm/lib/Transforms/Scalar/LoopRerollPass.cpp | 12 +- llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp | 2 +- llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp | 25 + llvm/lib/Transforms/Scalar/NewGVN.cpp | 35 +- .../Transforms/Scalar/RewriteStatepointsForGC.cpp | 51 +- llvm/lib/Transforms/Scalar/SCCP.cpp | 3 +- llvm/lib/Transforms/Scalar/Scalar.cpp | 2 +- .../Scalar/SeparateConstOffsetFromGEP.cpp | 6 +- llvm/lib/Transforms/Utils/CodeLayout.cpp | 942 +++++++++++++++ llvm/lib/Transforms/Utils/Debugify.cpp | 2 +- llvm/lib/Transforms/Utils/FunctionComparator.cpp | 16 +- llvm/lib/Transforms/Utils/Local.cpp | 12 + llvm/lib/Transforms/Utils/LoopPeel.cpp | 31 +- llvm/lib/Transforms/Utils/LoopUtils.cpp | 101 +- llvm/lib/Transforms/Utils/MetaRenamer.cpp | 67 +- .../Transforms/Utils/RelLookupTableConverter.cpp | 4 + .../Transforms/Utils/SampleProfileInference.cpp | 385 +++++- .../Transforms/Utils/ScalarEvolutionExpander.cpp | 6 +- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 2 +- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp | 293 +++-- llvm/lib/Transforms/Utils/ValueMapper.cpp | 6 + .../Vectorize/LoopVectorizationLegality.cpp | 89 +- .../Vectorize/LoopVectorizationPlanner.h | 38 +- llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 463 ++++---- llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp | 633 ++++++---- llvm/lib/Transforms/Vectorize/VPlan.cpp | 9 +- llvm/lib/Transforms/Vectorize/VPlan.h | 118 +- llvm/lib/Transforms/Vectorize/VPlanPredicator.cpp | 6 +- llvm/lib/Transforms/Vectorize/VPlanSLP.cpp | 5 +- llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp | 49 +- llvm/lib/Transforms/Vectorize/VPlanTransforms.h | 21 +- llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp | 26 + llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 6 +- 625 files changed, 23387 insertions(+), 10873 deletions(-) create mode 100644 llvm/lib/Analysis/CycleAnalysis.cpp create mode 100644 llvm/lib/Analysis/ModelUnderTrainingRunner.cpp create mode 100644 llvm/lib/Analysis/NoInferenceModelRunner.cpp delete mode 100644 llvm/lib/Analysis/ReleaseModeModelRunner.cpp create mode 100644 llvm/lib/CodeGen/MachineCycleAnalysis.cpp create mode 100644 llvm/lib/CodeGen/MachineSSAContext.cpp create mode 100644 llvm/lib/CodeGen/RegAllocEvictionAdvisor.cpp create mode 100644 llvm/lib/CodeGen/RegAllocScore.cpp create mode 100644 llvm/lib/CodeGen/RegAllocScore.h create mode 100644 llvm/lib/CodeGen/VLIWMachineScheduler.cpp create mode 100644 llvm/lib/Debuginfod/Debuginfod.cpp create mode 100644 llvm/lib/Debuginfod/HTTPClient.cpp create mode 100644 llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp create mode 100644 llvm/lib/IR/SSAContext.cpp create mode 100644 llvm/lib/ProfileData/InstrProfCorrelator.cpp delete mode 100644 llvm/lib/Support/HTTPClient.cpp create mode 100644 llvm/lib/Target/Hexagon/HexagonScheduleV69.td create mode 100644 llvm/lib/Target/PowerPC/PPCBack2BackFusion.def create mode 100644 llvm/lib/Transforms/Utils/CodeLayout.cpp (limited to 'llvm/lib') diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp index d030f74481cf..49199060786c 100644 --- a/llvm/lib/Analysis/AliasAnalysis.cpp +++ b/llvm/lib/Analysis/AliasAnalysis.cpp @@ -249,11 +249,11 @@ ModRefInfo AAResults::getModRefInfo(const CallBase *Call, bool IsMustAlias = true; ModRefInfo AllArgsMask = ModRefInfo::NoModRef; if (doesAccessArgPointees(MRB)) { - for (auto AI = Call->arg_begin(), AE = Call->arg_end(); AI != AE; ++AI) { - const Value *Arg = *AI; + for (const auto &I : llvm::enumerate(Call->args())) { + const Value *Arg = I.value(); if (!Arg->getType()->isPointerTy()) continue; - unsigned ArgIdx = std::distance(Call->arg_begin(), AI); + unsigned ArgIdx = I.index(); MemoryLocation ArgLoc = MemoryLocation::getForArgument(Call, ArgIdx, TLI); AliasResult ArgAlias = alias(ArgLoc, Loc, AAQI); @@ -696,14 +696,16 @@ ModRefInfo AAResults::getModRefInfo(const Instruction *I, case Instruction::AtomicRMW: return getModRefInfo((const AtomicRMWInst *)I, Loc, AAQIP); case Instruction::Call: - return getModRefInfo((const CallInst *)I, Loc, AAQIP); + case Instruction::CallBr: case Instruction::Invoke: - return getModRefInfo((const InvokeInst *)I, Loc, AAQIP); + return getModRefInfo((const CallBase *)I, Loc, AAQIP); case Instruction::CatchPad: return getModRefInfo((const CatchPadInst *)I, Loc, AAQIP); case Instruction::CatchRet: return getModRefInfo((const CatchReturnInst *)I, Loc, AAQIP); default: + assert(!I->mayReadOrWriteMemory() && + "Unhandled memory access instruction!"); return ModRefInfo::NoModRef; } } diff --git a/llvm/lib/Analysis/Analysis.cpp b/llvm/lib/Analysis/Analysis.cpp index db5167061509..177f38af13d8 100644 --- a/llvm/lib/Analysis/Analysis.cpp +++ b/llvm/lib/Analysis/Analysis.cpp @@ -35,6 +35,7 @@ void llvm::initializeAnalysis(PassRegistry &Registry) { initializeCFGOnlyPrinterLegacyPassPass(Registry); initializeCFLAndersAAWrapperPassPass(Registry); initializeCFLSteensAAWrapperPassPass(Registry); + initializeCycleInfoWrapperPassPass(Registry); initializeDependenceAnalysisWrapperPassPass(Registry); initializeDelinearizationPass(Registry); initializeDemandedBitsWrapperPassPass(Registry); diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp index 88b0f37b1d48..5f1bf2001d47 100644 --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -1699,6 +1699,7 @@ AliasResult BasicAAResult::aliasCheckRecursive( return Result; } else if (const GEPOperator *GV2 = dyn_cast(V2)) { AliasResult Result = aliasGEP(GV2, V2Size, V1, V1Size, O2, O1, AAQI); + Result.swap(); if (Result != AliasResult::MayAlias) return Result; } @@ -1709,6 +1710,7 @@ AliasResult BasicAAResult::aliasCheckRecursive( return Result; } else if (const PHINode *PN = dyn_cast(V2)) { AliasResult Result = aliasPHI(PN, V2Size, V1, V1Size, AAQI); + Result.swap(); if (Result != AliasResult::MayAlias) return Result; } @@ -1719,6 +1721,7 @@ AliasResult BasicAAResult::aliasCheckRecursive( return Result; } else if (const SelectInst *S2 = dyn_cast(V2)) { AliasResult Result = aliasSelect(S2, V2Size, V1, V1Size, AAQI); + Result.swap(); if (Result != AliasResult::MayAlias) return Result; } diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp index 8955658cb9e7..9b45f455be08 100644 --- a/llvm/lib/Analysis/CaptureTracking.cpp +++ b/llvm/lib/Analysis/CaptureTracking.cpp @@ -346,13 +346,16 @@ void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker, if (Tracker->captured(U)) return; - // Not captured if only passed via 'nocapture' arguments. Note that - // calling a function pointer does not in itself cause the pointer to + // Calling a function pointer does not in itself cause the pointer to // be captured. This is a subtle point considering that (for example) // the callee might return its own address. It is analogous to saying // that loading a value from a pointer does not cause the pointer to be // captured, even though the loaded value might be the pointer itself // (think of self-referential objects). + if (Call->isCallee(U)) + break; + + // Not captured if only passed via 'nocapture' arguments. if (Call->isDataOperand(U) && !Call->doesNotCapture(Call->getDataOperandNo(U))) { // The parameter is not marked 'nocapture' - captured. diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 3ed3b8902343..922b38e92785 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -352,6 +352,9 @@ Constant *llvm::ConstantFoldLoadThroughBitcast(Constant *C, Type *DestTy, const DataLayout &DL) { do { Type *SrcTy = C->getType(); + if (SrcTy == DestTy) + return C; + TypeSize DestSize = DL.getTypeSizeInBits(DestTy); TypeSize SrcSize = DL.getTypeSizeInBits(SrcTy); if (!TypeSize::isKnownGE(SrcSize, DestSize)) @@ -705,7 +708,8 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty, // is all undef or zero, we know what it loads. if (auto *GV = dyn_cast(getUnderlyingObject(C))) { if (GV->isConstant() && GV->hasDefinitiveInitializer()) { - if (GV->getInitializer()->isNullValue()) + if (GV->getInitializer()->isNullValue() && !Ty->isX86_MMXTy() && + !Ty->isX86_AMXTy()) return Constant::getNullValue(Ty); if (isa(GV->getInitializer())) return UndefValue::get(Ty); @@ -881,7 +885,7 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP, InnermostGEP = GEP; InBounds &= GEP->isInBounds(); - SmallVector NestedOps(GEP->op_begin() + 1, GEP->op_end()); + SmallVector NestedOps(llvm::drop_begin(GEP->operands())); // Do not try the incorporate the sub-GEP if some index is not a number. bool AllConstantInt = true; @@ -1774,15 +1778,8 @@ static bool mayFoldConstrained(ConstrainedFPIntrinsic *CI, // If the operation does not change exception status flags, it is safe // to fold. - if (St == APFloat::opStatus::opOK) { - // When FP exceptions are not ignored, intrinsic call will not be - // eliminated, because it is considered as having side effect. But we - // know that its evaluation does not raise exceptions, so side effect - // is absent. To allow removing the call, mark it as not accessing memory. - if (EB && *EB != fp::ExceptionBehavior::ebIgnore) - CI->addFnAttr(Attribute::ReadNone); + if (St == APFloat::opStatus::opOK) return true; - } // If evaluation raised FP exception, the result can depend on rounding // mode. If the latter is unknown, folding is not possible. @@ -2960,10 +2957,6 @@ static Constant *ConstantFoldFixedVectorCall( if (auto *Op = dyn_cast(Operands[0])) { unsigned Lanes = FVTy->getNumElements(); uint64_t Limit = Op->getZExtValue(); - // vctp64 are currently modelled as returning a v4i1, not a v2i1. Make - // sure we get the limit right in that case and set all relevant lanes. - if (IntrinsicID == Intrinsic::arm_mve_vctp64) - Limit *= 2; SmallVector NCs; for (unsigned i = 0; i < Lanes; i++) { diff --git a/llvm/lib/Analysis/CycleAnalysis.cpp b/llvm/lib/Analysis/CycleAnalysis.cpp new file mode 100644 index 000000000000..09c7ee67e05c --- /dev/null +++ b/llvm/lib/Analysis/CycleAnalysis.cpp @@ -0,0 +1,77 @@ +//===- CycleAnalysis.cpp - Compute CycleInfo for LLVM IR ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/CycleAnalysis.h" +#include "llvm/ADT/GenericCycleImpl.h" +#include "llvm/IR/CFG.h" +#include "llvm/InitializePasses.h" + +using namespace llvm; + +template class llvm::GenericCycleInfo; +template class llvm::GenericCycle; + +CycleInfo CycleAnalysis::run(Function &F, FunctionAnalysisManager &) { + CycleInfo CI; + CI.compute(F); + return CI; +} + +AnalysisKey CycleAnalysis::Key; + +CycleInfoPrinterPass::CycleInfoPrinterPass(raw_ostream &OS) : OS(OS) {} + +PreservedAnalyses CycleInfoPrinterPass::run(Function &F, + FunctionAnalysisManager &AM) { + OS << "CycleInfo for function: " << F.getName() << "\n"; + AM.getResult(F).print(OS); + + return PreservedAnalyses::all(); +} + +//===----------------------------------------------------------------------===// +// CycleInfoWrapperPass Implementation +//===----------------------------------------------------------------------===// +// +// The implementation details of the wrapper pass that holds a CycleInfo +// suitable for use with the legacy pass manager. +// +//===----------------------------------------------------------------------===// + +char CycleInfoWrapperPass::ID = 0; + +CycleInfoWrapperPass::CycleInfoWrapperPass() : FunctionPass(ID) { + initializeCycleInfoWrapperPassPass(*PassRegistry::getPassRegistry()); +} + +INITIALIZE_PASS_BEGIN(CycleInfoWrapperPass, "cycles", "Cycle Info Analysis", + true, true) +INITIALIZE_PASS_END(CycleInfoWrapperPass, "cycles", "Cycle Info Analysis", true, + true) + +void CycleInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); +} + +bool CycleInfoWrapperPass::runOnFunction(Function &Func) { + CI.clear(); + + F = &Func; + CI.compute(Func); + return false; +} + +void CycleInfoWrapperPass::print(raw_ostream &OS, const Module *) const { + OS << "CycleInfo for function: " << F->getName() << "\n"; + CI.print(OS); +} + +void CycleInfoWrapperPass::releaseMemory() { + CI.clear(); + F = nullptr; +} diff --git a/llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp b/llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp index d87fa849d839..31b2dafa29b4 100644 --- a/llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp +++ b/llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp @@ -16,6 +16,8 @@ #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/InlineSizeEstimatorAnalysis.h" #include "llvm/Analysis/MLInlineAdvisor.h" +#include "llvm/Analysis/ModelUnderTrainingRunner.h" +#include "llvm/Analysis/NoInferenceModelRunner.h" #include "llvm/Analysis/Utils/TFUtils.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/CommandLine.h" @@ -94,7 +96,6 @@ struct InlineEvent { /// Because this is a protobuf, we cannot just stream the events as they come. /// Internally, TrainingLogger stores data in column-major format, because that /// lines up with how TF SequenceExample represents it. -class ModelUnderTrainingRunner; class TrainingLogger final { public: TrainingLogger(StringRef LogFileName, const ModelUnderTrainingRunner *MUTR); @@ -261,65 +262,21 @@ private: const int64_t Mandatory; }; -/// A pseudo model runner. We use it to store feature values when collecting -/// logs for the default policy, but never ask it to 'run'. -class NoInferenceModelRunner : public MLModelRunner { -public: - NoInferenceModelRunner(LLVMContext &Ctx) - : MLModelRunner(Ctx), Features(NumberOfFeatures) {} - void setFeature(FeatureIndex Index, int64_t Value) override { - Features[static_cast(Index)] = Value; - } - - int64_t getFeature(int Index) const override { return Features[Index]; } - bool run() override { - llvm_unreachable("We shouldn't call run on this model runner."); - } - -private: - InlineFeatures Features; -}; - -/// ModelUnderTrainingRunner - training mode implementation. It uses TF C APIs -/// to dynamically load and evaluate a TF SavedModel -/// (https://www.tensorflow.org/guide/saved_model). Runtime performance is -/// sacrificed for ease of use while training. -class ModelUnderTrainingRunner final : public MLModelRunner { -public: - ModelUnderTrainingRunner(LLVMContext &Ctx, const std::string &ModelPath); - - bool run() override; +static const std::vector TrainingOnlyFeatures{ + TensorSpec::createSpec(TFFeedPrefix + "inlining_default", {1}), + TensorSpec::createSpec(TFFeedPrefix + "discount", {1}), + TensorSpec::createSpec(TFFeedPrefix + "reward", {1}), + TensorSpec::createSpec(TFFeedPrefix + "step_type", {1})}; - // Disallows copy and assign. - ModelUnderTrainingRunner(const ModelUnderTrainingRunner &) = delete; - ModelUnderTrainingRunner & - operator=(const ModelUnderTrainingRunner &) = delete; - - void setFeature(FeatureIndex Index, int64_t Value) override; - int64_t getFeature(int Index) const override; - bool isValid() const { return !!Evaluator; } - - const std::vector &outputLoggedFeatureSpecs() const { - return OutputSpecs; - } - - const Optional & - lastEvaluationResult() const { - return LastEvaluationResult; - } +static const std::vector getInputFeatures() { + std::vector InputSpecs; + for (size_t I = 0; I < NumberOfFeatures; ++I) + InputSpecs.push_back( + TensorSpec::createSpec(TFFeedPrefix + FeatureNameMap[I], {1})); + append_range(InputSpecs, TrainingOnlyFeatures); + return InputSpecs; +} -private: - std::unique_ptr Evaluator; - std::vector OutputSpecs; - Optional LastEvaluationResult; - - // The training framework needs some additional features. - const std::vector TrainingOnlyFeatures{ - TensorSpec::createSpec(TFFeedPrefix + "inlining_default", {1}), - TensorSpec::createSpec(TFFeedPrefix + "discount", {1}), - TensorSpec::createSpec(TFFeedPrefix + "reward", {1}), - TensorSpec::createSpec(TFFeedPrefix + "step_type", {1})}; -}; } // namespace TrainingLogger::TrainingLogger(StringRef LogFileName, @@ -353,7 +310,7 @@ void TrainingLogger::logInlineEvent(const InlineEvent &Event, const MLModelRunner &ModelRunner) { size_t CurrentFeature = 0; for (; CurrentFeature < NumberOfFeatures; ++CurrentFeature) { - int64_t F = ModelRunner.getFeature(CurrentFeature); + int64_t F = *ModelRunner.getTensor(CurrentFeature); L->logInt64Value(CurrentFeature, &F); } @@ -433,7 +390,9 @@ DevelopmentModeMLInlineAdvisor::getAdviceFromModel( return MLInlineAdvisor::getAdviceFromModel(CB, ORE); bool DefaultAdvice = GetDefaultAdvice(CB); - auto Recommendation = IsDoingInference ? ModelRunner->run() : DefaultAdvice; + auto Recommendation = + IsDoingInference ? static_cast(ModelRunner->evaluate()) + : DefaultAdvice; return std::make_unique( /*Advisor=*/this, /*CB=*/CB, /*ORE=*/ORE, /*Recommendation=*/Recommendation, @@ -458,49 +417,6 @@ size_t DevelopmentModeMLInlineAdvisor::getTotalSizeEstimate() { return Ret; } -ModelUnderTrainingRunner::ModelUnderTrainingRunner(LLVMContext &Ctx, - const std::string &ModelPath) - : MLModelRunner(Ctx) { - std::vector InputSpecs; - for (size_t I = 0; I < NumberOfFeatures; ++I) - InputSpecs.push_back( - TensorSpec::createSpec(TFFeedPrefix + FeatureNameMap[I], {1})); - append_range(InputSpecs, TrainingOnlyFeatures); - if (auto MaybeOutSpecs = - loadOutputSpecs(Ctx, DecisionName, ModelPath, TFOutputSpecOverride)) - OutputSpecs = std::move(*MaybeOutSpecs); - else - return; - - Evaluator = std::make_unique( - ModelPath, InputSpecs, [&](size_t I) { return OutputSpecs[I].Spec; }, - OutputSpecs.size()); - if (!Evaluator || !Evaluator->isValid()) { - Ctx.emitError("Failed to create inliner saved model evaluator"); - Evaluator.reset(); - return; - } -} - -bool ModelUnderTrainingRunner::run() { - LastEvaluationResult = Evaluator->evaluate(); - if (!LastEvaluationResult.hasValue()) { - Ctx.emitError("Error evaluating model."); - return false; - } - int64_t Decision = *LastEvaluationResult->getTensorValue(0); - return static_cast(Decision); -} - -int64_t ModelUnderTrainingRunner::getFeature(int Index) const { - return *Evaluator->getInput(Index); -} - -void ModelUnderTrainingRunner::setFeature(FeatureIndex Index, int64_t Value) { - size_t NumericIndex = static_cast(Index); - *(Evaluator->getInput(NumericIndex)) = Value; -} - std::unique_ptr llvm::getDevelopmentModeAdvisor( Module &M, ModuleAnalysisManager &MAM, std::function GetDefaultAdvice) { @@ -509,10 +425,13 @@ std::unique_ptr llvm::getDevelopmentModeAdvisor( ModelUnderTrainingRunner *MUTRPtr = nullptr; bool IsDoingInference = false; if (TFModelUnderTrainingPath.empty()) - Runner.reset(new NoInferenceModelRunner(Ctx)); + Runner.reset(new NoInferenceModelRunner(Ctx, getInputFeatures())); else { - auto MUTR = std::make_unique( - Ctx, TFModelUnderTrainingPath); + std::unique_ptr MUTR; + if (auto MaybeOutputSpecs = loadOutputSpecs( + Ctx, DecisionName, TFModelUnderTrainingPath, TFOutputSpecOverride)) + MUTR = std::make_unique( + Ctx, TFModelUnderTrainingPath, getInputFeatures(), *MaybeOutputSpecs); if (!MUTR || !MUTR->isValid()) { Ctx.emitError("Could not load the policy model from the provided path"); return nullptr; diff --git a/llvm/lib/Analysis/IVDescriptors.cpp b/llvm/lib/Analysis/IVDescriptors.cpp index cfe910df4e91..f5fa6748d053 100644 --- a/llvm/lib/Analysis/IVDescriptors.cpp +++ b/llvm/lib/Analysis/IVDescriptors.cpp @@ -933,7 +933,7 @@ bool RecurrenceDescriptor::isFirstOrderRecurrence( /// This function returns the identity element (or neutral element) for /// the operation K. Value *RecurrenceDescriptor::getRecurrenceIdentity(RecurKind K, Type *Tp, - FastMathFlags FMF) { + FastMathFlags FMF) const { switch (K) { case RecurKind::Xor: case RecurKind::Add: diff --git a/llvm/lib/Analysis/InlineAdvisor.cpp b/llvm/lib/Analysis/InlineAdvisor.cpp index 73d1eff1b968..140c88eb8b0d 100644 --- a/llvm/lib/Analysis/InlineAdvisor.cpp +++ b/llvm/lib/Analysis/InlineAdvisor.cpp @@ -40,6 +40,10 @@ static cl::opt " callsites processed by inliner but decided" " to be not inlined")); +static cl::opt EnableInlineDeferral("inline-deferral", cl::init(false), + cl::Hidden, + cl::desc("Enable deferred inlining")); + // An integer used to limit the cost of inline deferral. The default negative // number tells shouldBeDeferred to only take the secondary cost into account. static cl::opt @@ -136,8 +140,9 @@ llvm::Optional static getDefaultInlineAdvice( return getInlineCost(CB, Params, CalleeTTI, GetAssumptionCache, GetTLI, GetBFI, PSI, RemarksEnabled ? &ORE : nullptr); }; - return llvm::shouldInline(CB, GetInlineCost, ORE, - Params.EnableDeferral.getValueOr(false)); + return llvm::shouldInline( + CB, GetInlineCost, ORE, + Params.EnableDeferral.getValueOr(EnableInlineDeferral)); } std::unique_ptr @@ -409,8 +414,6 @@ llvm::shouldInline(CallBase &CB, << "' in other contexts"; }); setInlineRemark(CB, "deferred"); - // IC does not bool() to false, so get an InlineCost that will. - // This will not be inspected to make an error message. return None; } diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 22d2ce11cc90..4831b22b1d46 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2173,6 +2173,15 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, } } + // ((X | Y) ^ X ) & ((X | Y) ^ Y) --> 0 + // ((X | Y) ^ Y ) & ((X | Y) ^ X) --> 0 + BinaryOperator *Or; + if (match(Op0, m_c_Xor(m_Value(X), + m_CombineAnd(m_BinOp(Or), + m_c_Or(m_Deferred(X), m_Value(Y))))) && + match(Op1, m_c_Xor(m_Specific(Or), m_Specific(Y)))) + return Constant::getNullValue(Op0->getType()); + return nullptr; } @@ -2198,6 +2207,18 @@ static Value *simplifyOrLogic(Value *X, Value *Y) { Value *A, *B; + // (A ^ B) | (A | B) --> A | B + // (A ^ B) | (B | A) --> B | A + if (match(X, m_Xor(m_Value(A), m_Value(B))) && + match(Y, m_c_Or(m_Specific(A), m_Specific(B)))) + return Y; + + // ~(A ^ B) | (A | B) --> -1 + // ~(A ^ B) | (B | A) --> -1 + if (match(X, m_Not(m_Xor(m_Value(A), m_Value(B)))) && + match(Y, m_c_Or(m_Specific(A), m_Specific(B)))) + return ConstantInt::getAllOnesValue(Ty); + // (A & ~B) | (A ^ B) --> A ^ B // (~B & A) | (A ^ B) --> A ^ B // (A & ~B) | (B ^ A) --> B ^ A @@ -2214,18 +2235,33 @@ static Value *simplifyOrLogic(Value *X, Value *Y) { match(Y, m_c_And(m_Specific(A), m_Specific(B)))) return X; - // (A ^ B) | (A | B) --> A | B - // (A ^ B) | (B | A) --> B | A - if (match(X, m_Xor(m_Value(A), m_Value(B))) && - match(Y, m_c_Or(m_Specific(A), m_Specific(B)))) - return Y; - - // ~(A ^ B) | (A | B) --> -1 - // ~(A ^ B) | (B | A) --> -1 - if (match(X, m_Not(m_Xor(m_Value(A), m_Value(B)))) && - match(Y, m_c_Or(m_Specific(A), m_Specific(B)))) + // (~A | B) | (A ^ B) --> -1 + // (~A | B) | (B ^ A) --> -1 + // (B | ~A) | (A ^ B) --> -1 + // (B | ~A) | (B ^ A) --> -1 + if (match(X, m_c_Or(m_Not(m_Value(A)), m_Value(B))) && + match(Y, m_c_Xor(m_Specific(A), m_Specific(B)))) return ConstantInt::getAllOnesValue(Ty); + // (~A & B) | ~(A | B) --> ~A + // (~A & B) | ~(B | A) --> ~A + // (B & ~A) | ~(A | B) --> ~A + // (B & ~A) | ~(B | A) --> ~A + Value *NotA; + if (match(X, + m_c_And(m_CombineAnd(m_Value(NotA), m_NotForbidUndef(m_Value(A))), + m_Value(B))) && + match(Y, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) + return NotA; + + // ~(A ^ B) | (A & B) --> ~(A & B) + // ~(A ^ B) | (B & A) --> ~(A & B) + Value *NotAB; + if (match(X, m_CombineAnd(m_NotForbidUndef(m_Xor(m_Value(A), m_Value(B))), + m_Value(NotAB))) && + match(Y, m_c_And(m_Specific(A), m_Specific(B)))) + return NotAB; + return nullptr; } @@ -2259,27 +2295,6 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, if (Value *V = simplifyLogicOfAddSub(Op0, Op1, Instruction::Or)) return V; - Value *A, *B, *NotA; - - // (~A & B) | ~(A | B) --> ~A - // (~A & B) | ~(B | A) --> ~A - // (B & ~A) | ~(A | B) --> ~A - // (B & ~A) | ~(B | A) --> ~A - if (match(Op0, m_c_And(m_CombineAnd(m_Value(NotA), m_Not(m_Value(A))), - m_Value(B))) && - match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) - return NotA; - - // Commute the 'or' operands. - // ~(A | B) | (~A & B) --> ~A - // ~(B | A) | (~A & B) --> ~A - // ~(A | B) | (B & ~A) --> ~A - // ~(B | A) | (B & ~A) --> ~A - if (match(Op1, m_c_And(m_CombineAnd(m_Value(NotA), m_Not(m_Value(A))), - m_Value(B))) && - match(Op0, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) - return NotA; - // Rotated -1 is still -1: // (-1 << X) | (-1 >> (C - X)) --> -1 // (-1 >> X) | (-1 << (C - X)) --> -1 @@ -2335,6 +2350,7 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, } // (A & C1)|(B & C2) + Value *A, *B; const APInt *C1, *C2; if (match(Op0, m_And(m_Value(A), m_APInt(C1))) && match(Op1, m_And(m_Value(B), m_APInt(C2)))) { @@ -2696,9 +2712,17 @@ static Value *simplifyICmpOfBools(CmpInst::Predicate Pred, Value *LHS, if (!OpTy->isIntOrIntVectorTy(1)) return nullptr; - // A boolean compared to true/false can be simplified in 14 out of the 20 - // (10 predicates * 2 constants) possible combinations. Cases not handled here - // require a 'not' of the LHS, so those must be transformed in InstCombine. + // A boolean compared to true/false can be reduced in 14 out of the 20 + // (10 predicates * 2 constants) possible combinations. The other + // 6 cases require a 'not' of the LHS. + + auto ExtractNotLHS = [](Value *V) -> Value * { + Value *X; + if (match(V, m_Not(m_Value(X)))) + return X; + return nullptr; + }; + if (match(RHS, m_Zero())) { switch (Pred) { case CmpInst::ICMP_NE: // X != 0 -> X @@ -2706,6 +2730,13 @@ static Value *simplifyICmpOfBools(CmpInst::Predicate Pred, Value *LHS, case CmpInst::ICMP_SLT: // X X return LHS; + case CmpInst::ICMP_EQ: // not(X) == 0 -> X != 0 -> X + case CmpInst::ICMP_ULE: // not(X) <=u 0 -> X >u 0 -> X + case CmpInst::ICMP_SGE: // not(X) >=s 0 -> X X + if (Value *X = ExtractNotLHS(LHS)) + return X; + break; + case CmpInst::ICMP_ULT: // X false case CmpInst::ICMP_SGT: // X >s 0 -> false return getFalse(ITy); @@ -2723,6 +2754,13 @@ static Value *simplifyICmpOfBools(CmpInst::Predicate Pred, Value *LHS, case CmpInst::ICMP_SLE: // X <=s -1 -> X return LHS; + case CmpInst::ICMP_NE: // not(X) != 1 -> X == 1 -> X + case CmpInst::ICMP_ULT: // not(X) <=u 1 -> X >=u 1 -> X + case CmpInst::ICMP_SGT: // not(X) >s 1 -> X <=s -1 -> X + if (Value *X = ExtractNotLHS(LHS)) + return X; + break; + case CmpInst::ICMP_UGT: // X >u 1 -> false case CmpInst::ICMP_SLT: // X false return getFalse(ITy); @@ -5887,9 +5925,9 @@ static Value *simplifyIntrinsic(CallBase *Call, const SimplifyQuery &Q) { auto Attr = Call->getFunction()->getFnAttribute(Attribute::VScaleRange); if (!Attr.isValid()) return nullptr; - unsigned VScaleMin, VScaleMax; - std::tie(VScaleMin, VScaleMax) = Attr.getVScaleRangeArgs(); - if (VScaleMin == VScaleMax && VScaleMax != 0) + unsigned VScaleMin = Attr.getVScaleRangeMin(); + Optional VScaleMax = Attr.getVScaleRangeMax(); + if (VScaleMax && VScaleMin == VScaleMax) return ConstantInt::get(F->getReturnType(), VScaleMin); return nullptr; } diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp index 19a24ac6a484..6444518dc70c 100644 --- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp +++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp @@ -1568,11 +1568,12 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx, auto &DL = InnermostLoop->getHeader()->getModule()->getDataLayout(); uint64_t TypeByteSize = DL.getTypeAllocSize(ATy); + bool HasSameSize = + DL.getTypeStoreSizeInBits(ATy) == DL.getTypeStoreSizeInBits(BTy); uint64_t Stride = std::abs(StrideAPtr); const SCEVConstant *C = dyn_cast(Dist); if (!C) { - if (!isa(Dist) && - TypeByteSize == DL.getTypeAllocSize(BTy) && + if (!isa(Dist) && HasSameSize && isSafeDependenceDistance(DL, *(PSE.getSE()), *(PSE.getBackedgeTakenCount()), *Dist, Stride, TypeByteSize)) @@ -1587,7 +1588,7 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx, int64_t Distance = Val.getSExtValue(); // Attempt to prove strided accesses independent. - if (std::abs(Distance) > 0 && Stride > 1 && ATy == BTy && + if (std::abs(Distance) > 0 && Stride > 1 && HasSameSize && areStridedAccessesIndependent(std::abs(Distance), Stride, TypeByteSize)) { LLVM_DEBUG(dbgs() << "LAA: Strided accesses are independent\n"); return Dependence::NoDep; @@ -1598,7 +1599,7 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx, bool IsTrueDataDependence = (AIsWrite && !BIsWrite); if (IsTrueDataDependence && EnableForwardingConflictDetection && (couldPreventStoreLoadForward(Val.abs().getZExtValue(), TypeByteSize) || - ATy != BTy)) { + !HasSameSize)) { LLVM_DEBUG(dbgs() << "LAA: Forward but may prevent st->ld forwarding\n"); return Dependence::ForwardButPreventsForwarding; } @@ -1608,21 +1609,19 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx, } // Write to the same location with the same size. - // Could be improved to assert type sizes are the same (i32 == float, etc). if (Val == 0) { - if (ATy == BTy) + if (HasSameSize) return Dependence::Forward; LLVM_DEBUG( - dbgs() << "LAA: Zero dependence difference but different types\n"); + dbgs() << "LAA: Zero dependence difference but different type sizes\n"); return Dependence::Unknown; } assert(Val.isStrictlyPositive() && "Expect a positive value"); - if (ATy != BTy) { - LLVM_DEBUG( - dbgs() - << "LAA: ReadWrite-Write positive dependency with different types\n"); + if (!HasSameSize) { + LLVM_DEBUG(dbgs() << "LAA: ReadWrite-Write positive dependency with " + "different type sizes\n"); return Dependence::Unknown; } diff --git a/llvm/lib/Analysis/MLInlineAdvisor.cpp b/llvm/lib/Analysis/MLInlineAdvisor.cpp index 6fc4c42bdd71..f5a65cd2b689 100644 --- a/llvm/lib/Analysis/MLInlineAdvisor.cpp +++ b/llvm/lib/Analysis/MLInlineAdvisor.cpp @@ -35,6 +35,21 @@ using namespace llvm; +#ifdef LLVM_HAVE_TF_AOT +#include "llvm/Analysis/ReleaseModeModelRunner.h" +// codegen-ed file +#include "InlinerSizeModel.h" // NOLINT +#include "llvm/Analysis/InlineModelFeatureMaps.h" + +std::unique_ptr +llvm::getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM) { + auto AOTRunner = + std::make_unique>( + M.getContext(), FeatureNameMap, DecisionName); + return std::make_unique(M, MAM, std::move(AOTRunner)); +} +#endif + #define DEBUG_TYPE "inline-ml" static cl::opt SizeIncreaseThreshold( @@ -245,29 +260,32 @@ std::unique_ptr MLInlineAdvisor::getAdviceImpl(CallBase &CB) { auto &CallerBefore = FAM.getResult(Caller); auto &CalleeBefore = FAM.getResult(Callee); - ModelRunner->setFeature(FeatureIndex::CalleeBasicBlockCount, - CalleeBefore.BasicBlockCount); - ModelRunner->setFeature(FeatureIndex::CallSiteHeight, - FunctionLevels[&Caller]); - ModelRunner->setFeature(FeatureIndex::NodeCount, NodeCount); - ModelRunner->setFeature(FeatureIndex::NrCtantParams, NrCtantParams); - ModelRunner->setFeature(FeatureIndex::EdgeCount, EdgeCount); - ModelRunner->setFeature(FeatureIndex::CallerUsers, CallerBefore.Uses); - ModelRunner->setFeature(FeatureIndex::CallerConditionallyExecutedBlocks, - CallerBefore.BlocksReachedFromConditionalInstruction); - ModelRunner->setFeature(FeatureIndex::CallerBasicBlockCount, - CallerBefore.BasicBlockCount); - ModelRunner->setFeature(FeatureIndex::CalleeConditionallyExecutedBlocks, - CalleeBefore.BlocksReachedFromConditionalInstruction); - ModelRunner->setFeature(FeatureIndex::CalleeUsers, CalleeBefore.Uses); - ModelRunner->setFeature(FeatureIndex::CostEstimate, CostEstimate); + *ModelRunner->getTensor(FeatureIndex::CalleeBasicBlockCount) = + CalleeBefore.BasicBlockCount; + *ModelRunner->getTensor(FeatureIndex::CallSiteHeight) = + FunctionLevels[&Caller]; + *ModelRunner->getTensor(FeatureIndex::NodeCount) = NodeCount; + *ModelRunner->getTensor(FeatureIndex::NrCtantParams) = NrCtantParams; + *ModelRunner->getTensor(FeatureIndex::EdgeCount) = EdgeCount; + *ModelRunner->getTensor(FeatureIndex::CallerUsers) = + CallerBefore.Uses; + *ModelRunner->getTensor( + FeatureIndex::CallerConditionallyExecutedBlocks) = + CallerBefore.BlocksReachedFromConditionalInstruction; + *ModelRunner->getTensor(FeatureIndex::CallerBasicBlockCount) = + CallerBefore.BasicBlockCount; + *ModelRunner->getTensor( + FeatureIndex::CalleeConditionallyExecutedBlocks) = + CalleeBefore.BlocksReachedFromConditionalInstruction; + *ModelRunner->getTensor(FeatureIndex::CalleeUsers) = + CalleeBefore.Uses; + *ModelRunner->getTensor(FeatureIndex::CostEstimate) = CostEstimate; // Add the cost features for (size_t I = 0; I < static_cast(InlineCostFeatureIndex::NumberOfFeatures); ++I) { - ModelRunner->setFeature( - inlineCostFeatureToMlFeature(static_cast(I)), - CostFeatures->at(I)); + *ModelRunner->getTensor(inlineCostFeatureToMlFeature( + static_cast(I))) = CostFeatures->at(I); } return getAdviceFromModel(CB, ORE); @@ -276,7 +294,8 @@ std::unique_ptr MLInlineAdvisor::getAdviceImpl(CallBase &CB) { std::unique_ptr MLInlineAdvisor::getAdviceFromModel(CallBase &CB, OptimizationRemarkEmitter &ORE) { - return std::make_unique(this, CB, ORE, ModelRunner->run()); + return std::make_unique( + this, CB, ORE, static_cast(ModelRunner->evaluate())); } std::unique_ptr MLInlineAdvisor::getMandatoryAdvice(CallBase &CB, @@ -302,7 +321,8 @@ void MLInlineAdvice::reportContextForRemark( using namespace ore; OR << NV("Callee", Callee->getName()); for (size_t I = 0; I < NumberOfFeatures; ++I) - OR << NV(FeatureNameMap[I], getAdvisor()->getModelRunner().getFeature(I)); + OR << NV(FeatureNameMap[I], + *getAdvisor()->getModelRunner().getTensor(I)); OR << NV("ShouldInline", isInliningRecommended()); } diff --git a/llvm/lib/Analysis/MemDerefPrinter.cpp b/llvm/lib/Analysis/MemDerefPrinter.cpp index 1b16e1a9bcb2..30937a2e4931 100644 --- a/llvm/lib/Analysis/MemDerefPrinter.cpp +++ b/llvm/lib/Analysis/MemDerefPrinter.cpp @@ -59,8 +59,8 @@ bool MemDerefPrinter::runOnFunction(Function &F) { Value *PO = LI->getPointerOperand(); if (isDereferenceablePointer(PO, LI->getType(), DL)) Deref.push_back(PO); - if (isDereferenceableAndAlignedPointer( - PO, LI->getType(), MaybeAlign(LI->getAlignment()), DL)) + if (isDereferenceableAndAlignedPointer(PO, LI->getType(), + MaybeAlign(LI->getAlign()), DL)) DerefAndAligned.insert(PO); } } @@ -94,8 +94,8 @@ PreservedAnalyses MemDerefPrinterPass::run(Function &F, Value *PO = LI->getPointerOperand(); if (isDereferenceablePointer(PO, LI->getType(), DL)) Deref.push_back(PO); - if (isDereferenceableAndAlignedPointer( - PO, LI->getType(), MaybeAlign(LI->getAlignment()), DL)) + if (isDereferenceableAndAlignedPointer(PO, LI->getType(), + MaybeAlign(LI->getAlign()), DL)) DerefAndAligned.insert(PO); } } diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index 4f2b5b34304d..ffdd7a2cfd4b 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -592,9 +592,9 @@ STATISTIC(ObjectVisitorArgument, STATISTIC(ObjectVisitorLoad, "Number of load instructions with unsolved size and offset"); -APInt ObjectSizeOffsetVisitor::align(APInt Size, uint64_t Alignment) { +APInt ObjectSizeOffsetVisitor::align(APInt Size, MaybeAlign Alignment) { if (Options.RoundToAlign && Alignment) - return APInt(IntTyBits, alignTo(Size.getZExtValue(), Align(Alignment))); + return APInt(IntTyBits, alignTo(Size.getZExtValue(), Alignment)); return Size; } @@ -669,7 +669,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) { APInt Size(IntTyBits, DL.getTypeAllocSize(I.getAllocatedType())); if (!I.isArrayAllocation()) - return std::make_pair(align(Size, I.getAlignment()), Zero); + return std::make_pair(align(Size, I.getAlign()), Zero); Value *ArraySize = I.getArraySize(); if (const ConstantInt *C = dyn_cast(ArraySize)) { @@ -679,8 +679,8 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) { bool Overflow; Size = Size.umul_ov(NumElems, Overflow); - return Overflow ? unknown() : std::make_pair(align(Size, I.getAlignment()), - Zero); + return Overflow ? unknown() + : std::make_pair(align(Size, I.getAlign()), Zero); } return unknown(); } @@ -694,7 +694,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitArgument(Argument &A) { } APInt Size(IntTyBits, DL.getTypeAllocSize(MemoryTy)); - return std::make_pair(align(Size, A.getParamAlignment()), Zero); + return std::make_pair(align(Size, A.getParamAlign()), Zero); } SizeOffsetType ObjectSizeOffsetVisitor::visitCallBase(CallBase &CB) { @@ -800,7 +800,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitGlobalVariable(GlobalVariable &GV){ return unknown(); APInt Size(IntTyBits, DL.getTypeAllocSize(GV.getValueType())); - return std::make_pair(align(Size, GV.getAlignment()), Zero); + return std::make_pair(align(Size, GV.getAlign()), Zero); } SizeOffsetType ObjectSizeOffsetVisitor::visitIntToPtrInst(IntToPtrInst&) { diff --git a/llvm/lib/Analysis/MemoryLocation.cpp b/llvm/lib/Analysis/MemoryLocation.cpp index 854ba83bd34a..a877b19df866 100644 --- a/llvm/lib/Analysis/MemoryLocation.cpp +++ b/llvm/lib/Analysis/MemoryLocation.cpp @@ -101,13 +101,8 @@ MemoryLocation MemoryLocation::getForSource(const AtomicMemTransferInst *MTI) { } MemoryLocation MemoryLocation::getForSource(const AnyMemTransferInst *MTI) { - auto Size = LocationSize::afterPointer(); - if (ConstantInt *C = dyn_cast(MTI->getLength())) - Size = LocationSize::precise(C->getValue().getZExtValue()); - - // memcpy/memmove can have AA tags. For memcpy, they apply - // to both the source and the destination. - return MemoryLocation(MTI->getRawSource(), Size, MTI->getAAMetadata()); + assert(MTI->getRawSource() == MTI->getArgOperand(1)); + return getForArgument(MTI, 1, nullptr); } MemoryLocation MemoryLocation::getForDest(const MemIntrinsic *MI) { @@ -119,13 +114,47 @@ MemoryLocation MemoryLocation::getForDest(const AtomicMemIntrinsic *MI) { } MemoryLocation MemoryLocation::getForDest(const AnyMemIntrinsic *MI) { - auto Size = LocationSize::afterPointer(); - if (ConstantInt *C = dyn_cast(MI->getLength())) - Size = LocationSize::precise(C->getValue().getZExtValue()); + assert(MI->getRawDest() == MI->getArgOperand(0)); + return getForArgument(MI, 0, nullptr); +} + +Optional +MemoryLocation::getForDest(const CallBase *CB, const TargetLibraryInfo &TLI) { + if (!CB->onlyAccessesArgMemory()) + return None; + + if (CB->hasOperandBundles()) + // TODO: remove implementation restriction + return None; + + Value *UsedV = nullptr; + Optional UsedIdx; + for (unsigned i = 0; i < CB->arg_size(); i++) { + if (!CB->getArgOperand(i)->getType()->isPointerTy()) + continue; + if (CB->onlyReadsMemory(i)) + continue; + if (!UsedV) { + // First potentially writing parameter + UsedV = CB->getArgOperand(i); + UsedIdx = i; + continue; + } + UsedIdx = None; + if (UsedV != CB->getArgOperand(i)) + // Can't describe writing to two distinct locations. + // TODO: This results in an inprecision when two values derived from the + // same object are passed as arguments to the same function. + return None; + } + if (!UsedV) + // We don't currently have a way to represent a "does not write" result + // and thus have to be conservative and return unknown. + return None; - // memcpy/memmove can have AA tags. For memcpy, they apply - // to both the source and the destination. - return MemoryLocation(MI->getRawDest(), Size, MI->getAAMetadata()); + if (UsedIdx) + return getForArgument(CB, *UsedIdx, &TLI); + return MemoryLocation::getBeforeOrAfter(UsedV, CB->getAAMetadata()); } MemoryLocation MemoryLocation::getForArgument(const CallBase *Call, @@ -145,6 +174,9 @@ MemoryLocation MemoryLocation::getForArgument(const CallBase *Call, case Intrinsic::memcpy: case Intrinsic::memcpy_inline: case Intrinsic::memmove: + case Intrinsic::memcpy_element_unordered_atomic: + case Intrinsic::memmove_element_unordered_atomic: + case Intrinsic::memset_element_unordered_atomic: assert((ArgIdx == 0 || ArgIdx == 1) && "Invalid argument index for memory intrinsic"); if (ConstantInt *LenCI = dyn_cast(II->getArgOperand(2))) @@ -204,6 +236,10 @@ MemoryLocation MemoryLocation::getForArgument(const CallBase *Call, II->getArgOperand(1)->getType())), AATags); } + + assert( + !isa(II) && + "all memory transfer intrinsics should be handled by the switch above"); } // We can bound the aliasing properties of memset_pattern16 just as we can @@ -213,6 +249,12 @@ MemoryLocation MemoryLocation::getForArgument(const CallBase *Call, LibFunc F; if (TLI && TLI->getLibFunc(*Call, F) && TLI->has(F)) { switch (F) { + case LibFunc_strcpy: + case LibFunc_strcat: + case LibFunc_strncat: + assert((ArgIdx == 0 || ArgIdx == 1) && "Invalid argument index for str function"); + return MemoryLocation::getAfter(Arg, AATags); + case LibFunc_memset_chk: { assert(ArgIdx == 0 && "Invalid argument index for memset_chk"); LocationSize Size = LocationSize::afterPointer(); @@ -236,10 +278,18 @@ MemoryLocation MemoryLocation::getForArgument(const CallBase *Call, return MemoryLocation(Arg, Size, AATags); } case LibFunc_memset_pattern16: + case LibFunc_memset_pattern4: + case LibFunc_memset_pattern8: assert((ArgIdx == 0 || ArgIdx == 1) && "Invalid argument index for memset_pattern16"); - if (ArgIdx == 1) - return MemoryLocation(Arg, LocationSize::precise(16), AATags); + if (ArgIdx == 1) { + unsigned Size = 16; + if (F == LibFunc_memset_pattern4) + Size = 4; + else if (F == LibFunc_memset_pattern8) + Size = 8; + return MemoryLocation(Arg, LocationSize::precise(Size), AATags); + } if (const ConstantInt *LenCI = dyn_cast(Call->getArgOperand(2))) return MemoryLocation(Arg, LocationSize::precise(LenCI->getZExtValue()), @@ -274,7 +324,6 @@ MemoryLocation MemoryLocation::getForArgument(const CallBase *Call, break; }; } - // FIXME: Handle memset_pattern4 and memset_pattern8 also. return MemoryLocation::getBeforeOrAfter(Call->getArgOperand(ArgIdx), AATags); } diff --git a/llvm/lib/Analysis/ModelUnderTrainingRunner.cpp b/llvm/lib/Analysis/ModelUnderTrainingRunner.cpp new file mode 100644 index 000000000000..941458f648bc --- /dev/null +++ b/llvm/lib/Analysis/ModelUnderTrainingRunner.cpp @@ -0,0 +1,49 @@ +//===- ModelUnderTrainingRunner.cpp - 'development' mode runner -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of a MLModelRunner for 'development' mode, i.e. evaluation +// happens off a model that's provided from the command line and is interpreted. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#if defined(LLVM_HAVE_TF_API) + +#include "llvm/Analysis/ModelUnderTrainingRunner.h" + +using namespace llvm; + +ModelUnderTrainingRunner::ModelUnderTrainingRunner( + LLVMContext &Ctx, const std::string &ModelPath, + const std::vector &InputSpecs, + const std::vector &OutputSpecs) + : MLModelRunner(Ctx), OutputSpecs(OutputSpecs) { + Evaluator = std::make_unique( + ModelPath, InputSpecs, [&](size_t I) { return OutputSpecs[I].Spec; }, + OutputSpecs.size()); + if (!Evaluator || !Evaluator->isValid()) { + Ctx.emitError("Failed to create inliner saved model evaluator"); + Evaluator.reset(); + return; + } +} + +void *ModelUnderTrainingRunner::evaluateUntyped() { + LastEvaluationResult = Evaluator->evaluate(); + if (!LastEvaluationResult.hasValue()) { + Ctx.emitError("Error evaluating model."); + return nullptr; + } + return LastEvaluationResult->getUntypedTensorValue(0); +} + +void *ModelUnderTrainingRunner::getTensorUntyped(size_t Index) { + return Evaluator->getUntypedInput(Index); +} + +#endif // defined(LLVM_HAVE_TF_API) diff --git a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp index d80814852e19..2880ca62a7f8 100644 --- a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp +++ b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -234,6 +234,18 @@ static bool isNonVolatileStore(const Instruction *I) { return false; } +// Returns true if the function definition must be unreachable. +// +// Note if this helper function returns true, `F` is guaranteed +// to be unreachable; if it returns false, `F` might still +// be unreachable but not covered by this helper function. +static bool mustBeUnreachableFunction(const Function &F) { + // A function must be unreachable if its entry block ends with an + // 'unreachable'. + assert(!F.isDeclaration()); + return isa(F.getEntryBlock().getTerminator()); +} + static void computeFunctionSummary( ModuleSummaryIndex &Index, const Module &M, const Function &F, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, DominatorTree &DT, @@ -488,7 +500,8 @@ static void computeFunctionSummary( // Don't try to import functions with noinline attribute. F.getAttributes().hasFnAttr(Attribute::NoInline), F.hasFnAttribute(Attribute::AlwaysInline), - F.hasFnAttribute(Attribute::NoUnwind), MayThrow, HasUnknownCall}; + F.hasFnAttribute(Attribute::NoUnwind), MayThrow, HasUnknownCall, + mustBeUnreachableFunction(F)}; std::vector ParamAccesses; if (auto *SSI = GetSSICallback(F)) ParamAccesses = SSI->getParamAccesses(Index); @@ -737,7 +750,8 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex( F->hasFnAttribute(Attribute::AlwaysInline), F->hasFnAttribute(Attribute::NoUnwind), /* MayThrow */ true, - /* HasUnknownCall */ true}, + /* HasUnknownCall */ true, + /* MustBeUnreachable */ false}, /*EntryCount=*/0, ArrayRef{}, ArrayRef{}, ArrayRef{}, diff --git a/llvm/lib/Analysis/NoInferenceModelRunner.cpp b/llvm/lib/Analysis/NoInferenceModelRunner.cpp new file mode 100644 index 000000000000..02ece6aa3900 --- /dev/null +++ b/llvm/lib/Analysis/NoInferenceModelRunner.cpp @@ -0,0 +1,33 @@ +//===- NoInferenceModelRunner.cpp - noop ML model runner ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A pseudo model runner. We use it to store feature values when collecting +// logs for the default policy, in 'development' mode, but never ask it to +// 'run'. +//===----------------------------------------------------------------------===// +#include "llvm/Config/config.h" +#if defined(LLVM_HAVE_TF_API) + +#include "llvm/Analysis/NoInferenceModelRunner.h" +#include "llvm/Analysis/Utils/TFUtils.h" + +using namespace llvm; + +NoInferenceModelRunner::NoInferenceModelRunner( + LLVMContext &Ctx, const std::vector &Inputs) + : MLModelRunner(Ctx) { + ValuesBuffer.reserve(Inputs.size()); + for (const auto &TS : Inputs) + ValuesBuffer.push_back(std::make_unique(TS.getElementCount() * + TS.getElementByteSize())); +} + +void *NoInferenceModelRunner::getTensorUntyped(size_t Index) { + return ValuesBuffer[Index].get(); +} +#endif // defined(LLVM_HAVE_TF_API) diff --git a/llvm/lib/Analysis/ReleaseModeModelRunner.cpp b/llvm/lib/Analysis/ReleaseModeModelRunner.cpp deleted file mode 100644 index d2bf95388066..000000000000 --- a/llvm/lib/Analysis/ReleaseModeModelRunner.cpp +++ /dev/null @@ -1,90 +0,0 @@ -//===- ReleaseModeModelRunner.cpp - Fast, precompiled model runner -------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements a model runner wrapping an AOT compiled ML model. -// Only inference is supported. -// -//===----------------------------------------------------------------------===// -#include "llvm/Config/config.h" -#if defined(LLVM_HAVE_TF_AOT) - -#include "llvm/Analysis/InlineModelFeatureMaps.h" -#include "llvm/Analysis/MLInlineAdvisor.h" - -// codegen-ed file -#include "InlinerSizeModel.h" // NOLINT - -#include -#include - -using namespace llvm; -namespace { - -const char FeedPrefix[] = "feed_"; -const char FetchPrefix[] = "fetch_"; - -/// MLModelRunner - production mode implementation. It uses a AOT-compiled -/// SavedModel for efficient execution. -class ReleaseModeModelRunner final : public MLModelRunner { -public: - ReleaseModeModelRunner(LLVMContext &Ctx); - virtual ~ReleaseModeModelRunner() = default; - - bool run() override; - - void setFeature(FeatureIndex Index, int64_t Value) override; - int64_t getFeature(int Index) const override; - -private: - std::vector FeatureIndices; - int32_t ResultIndex = -1; - std::unique_ptr CompiledModel; -}; -} // namespace - -ReleaseModeModelRunner::ReleaseModeModelRunner(LLVMContext &Ctx) - : MLModelRunner(Ctx), - CompiledModel(std::make_unique()) { - assert(CompiledModel && "The CompiledModel should be valid"); - - FeatureIndices.resize(NumberOfFeatures); - - for (size_t I = 0; I < NumberOfFeatures; ++I) { - const int Index = - CompiledModel->LookupArgIndex(FeedPrefix + FeatureNameMap[I]); - assert(Index >= 0 && "Cannot find Feature in inlining model"); - FeatureIndices[I] = Index; - } - - ResultIndex = - CompiledModel->LookupResultIndex(std::string(FetchPrefix) + DecisionName); - assert(ResultIndex >= 0 && "Cannot find DecisionName in inlining model"); -} - -int64_t ReleaseModeModelRunner::getFeature(int Index) const { - return *static_cast( - CompiledModel->arg_data(FeatureIndices[Index])); -} - -void ReleaseModeModelRunner::setFeature(FeatureIndex Index, int64_t Value) { - *static_cast(CompiledModel->arg_data( - FeatureIndices[static_cast(Index)])) = Value; -} - -bool ReleaseModeModelRunner::run() { - CompiledModel->Run(); - return static_cast( - *static_cast(CompiledModel->result_data(ResultIndex))); -} - -std::unique_ptr -llvm::getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM) { - auto AOTRunner = std::make_unique(M.getContext()); - return std::make_unique(M, MAM, std::move(AOTRunner)); -} -#endif // defined(LLVM_HAVE_TF_AOT) diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 7dc7f9904c70..0c3f32295ae1 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -8829,11 +8829,10 @@ const SCEV *ScalarEvolution::getSCEVAtScope(const SCEV *V, const Loop *L) { for (auto &LS : reverse(ValuesAtScopes[V])) if (LS.first == L) { LS.second = C; + if (!isa(C)) + ValuesAtScopesUsers[C].push_back({L, V}); break; } - - if (!isa(C)) - ValuesAtScopesUsers[C].push_back({L, V}); return C; } @@ -13058,11 +13057,13 @@ void ScalarEvolution::verify() const { Worklist.append(L->begin(), L->end()); } for (auto &KV : ValueExprMap) { +#ifndef NDEBUG // Check for SCEV expressions referencing invalid/deleted loops. if (auto *AR = dyn_cast(KV.second)) { assert(ValidLoops.contains(AR->getLoop()) && "AddRec references invalid loop"); } +#endif // Check that the value is also part of the reverse map. auto It = ExprValueMap.find(KV.second); @@ -13122,7 +13123,7 @@ void ScalarEvolution::verify() const { is_contained(It->second, std::make_pair(L, Value))) continue; dbgs() << "Value: " << *Value << ", Loop: " << *L << ", ValueAtScope: " - << ValueAtScope << " missing in ValuesAtScopesUsers\n"; + << *ValueAtScope << " missing in ValuesAtScopesUsers\n"; std::abort(); } } @@ -13139,7 +13140,7 @@ void ScalarEvolution::verify() const { is_contained(It->second, std::make_pair(L, ValueAtScope))) continue; dbgs() << "Value: " << *Value << ", Loop: " << *L << ", ValueAtScope: " - << ValueAtScope << " missing in ValuesAtScopes\n"; + << *ValueAtScope << " missing in ValuesAtScopes\n"; std::abort(); } } @@ -13958,11 +13959,12 @@ const SCEV *ScalarEvolution::applyLoopGuards(const SCEV *Expr, const Loop *L) { ExprsToRewrite.push_back(LHS); } }; - // Starting at the loop predecessor, climb up the predecessor chain, as long - // as there are predecessors that can be found that have unique successors - // leading to the original header. + // First, collect conditions from dominating branches. Starting at the loop + // predecessor, climb up the predecessor chain, as long as there are + // predecessors that can be found that have unique successors leading to the + // original header. // TODO: share this logic with isLoopEntryGuardedByCond. - DenseMap RewriteMap; + SmallVector> Terms; for (std::pair Pair( L->getLoopPredecessor(), L->getHeader()); Pair.first; Pair = getPredecessorWithUniqueSuccessorForBB(Pair.first)) { @@ -13972,10 +13974,20 @@ const SCEV *ScalarEvolution::applyLoopGuards(const SCEV *Expr, const Loop *L) { if (!LoopEntryPredicate || LoopEntryPredicate->isUnconditional()) continue; - bool EnterIfTrue = LoopEntryPredicate->getSuccessor(0) == Pair.second; + Terms.emplace_back(LoopEntryPredicate->getCondition(), + LoopEntryPredicate->getSuccessor(0) == Pair.second); + } + + // Now apply the information from the collected conditions to RewriteMap. + // Conditions are processed in reverse order, so the earliest conditions is + // processed first. This ensures the SCEVs with the shortest dependency chains + // are constructed first. + DenseMap RewriteMap; + for (auto &E : reverse(Terms)) { + bool EnterIfTrue = E.second; SmallVector Worklist; SmallPtrSet Visited; - Worklist.push_back(LoopEntryPredicate->getCondition()); + Worklist.push_back(E.first); while (!Worklist.empty()) { Value *Cond = Worklist.pop_back_val(); if (!Visited.insert(Cond).second) diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp index 72fbd5ad3f68..02923c2c7eb1 100644 --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -238,9 +238,8 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, // e.g., x86_64-pc-windows-msvc18. bool hasPartialC99 = true; if (T.isKnownWindowsMSVCEnvironment()) { - unsigned Major, Minor, Micro; - T.getEnvironmentVersion(Major, Minor, Micro); - hasPartialC99 = (Major == 0 || Major >= 19); + VersionTuple Version = T.getEnvironmentVersion(); + hasPartialC99 = (Version.getMajor() == 0 || Version.getMajor() >= 19); } // Latest targets support C89 math functions, in part. diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp index 5067f493f02d..6aa9a77391dc 100644 --- a/llvm/lib/Analysis/TargetTransformInfo.cpp +++ b/llvm/lib/Analysis/TargetTransformInfo.cpp @@ -982,10 +982,10 @@ bool TargetTransformInfo::areInlineCompatible(const Function *Caller, return TTIImpl->areInlineCompatible(Caller, Callee); } -bool TargetTransformInfo::areFunctionArgsABICompatible( +bool TargetTransformInfo::areTypesABICompatible( const Function *Caller, const Function *Callee, - SmallPtrSetImpl &Args) const { - return TTIImpl->areFunctionArgsABICompatible(Caller, Callee, Args); + const ArrayRef &Types) const { + return TTIImpl->areTypesABICompatible(Caller, Callee, Types); } bool TargetTransformInfo::isIndexedLoadLegal(MemIndexedMode Mode, @@ -1072,8 +1072,13 @@ bool TargetTransformInfo::supportsScalableVectors() const { return TTIImpl->supportsScalableVectors(); } -bool TargetTransformInfo::hasActiveVectorLength() const { - return TTIImpl->hasActiveVectorLength(); +bool TargetTransformInfo::enableScalableVectorization() const { + return TTIImpl->enableScalableVectorization(); +} + +bool TargetTransformInfo::hasActiveVectorLength(unsigned Opcode, Type *DataType, + Align Alignment) const { + return TTIImpl->hasActiveVectorLength(Opcode, DataType, Alignment); } InstructionCost diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 1c41c77a8cfb..fc378f97de0b 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1154,7 +1154,7 @@ static void computeKnownBitsFromOperator(const Operator *I, // If the negate has an NSW flag we can assume the sign bit of the result // will be 0 because that makes abs(INT_MIN) undefined. if (match(RHS, m_Neg(m_Specific(LHS))) && - Q.IIQ.hasNoSignedWrap(cast(RHS))) + Q.IIQ.hasNoSignedWrap(cast(RHS))) Known.Zero.setSignBit(); } @@ -1709,23 +1709,25 @@ static void computeKnownBitsFromOperator(const Operator *I, !II->getFunction()->hasFnAttribute(Attribute::VScaleRange)) break; - auto VScaleRange = II->getFunction() - ->getFnAttribute(Attribute::VScaleRange) - .getVScaleRangeArgs(); + auto Attr = II->getFunction()->getFnAttribute(Attribute::VScaleRange); + Optional VScaleMax = Attr.getVScaleRangeMax(); - if (VScaleRange.second == 0) + if (!VScaleMax) break; + unsigned VScaleMin = Attr.getVScaleRangeMin(); + // If vscale min = max then we know the exact value at compile time // and hence we know the exact bits. - if (VScaleRange.first == VScaleRange.second) { - Known.One = VScaleRange.first; - Known.Zero = VScaleRange.first; + if (VScaleMin == VScaleMax) { + Known.One = VScaleMin; + Known.Zero = VScaleMin; Known.Zero.flipAllBits(); break; } - unsigned FirstZeroHighBit = 32 - countLeadingZeros(VScaleRange.second); + unsigned FirstZeroHighBit = + 32 - countLeadingZeros(VScaleMax.getValue()); if (FirstZeroHighBit < BitWidth) Known.Zero.setBitsFrom(FirstZeroHighBit); @@ -4676,8 +4678,8 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V, return false; const DataLayout &DL = LI->getModule()->getDataLayout(); return isDereferenceableAndAlignedPointer( - LI->getPointerOperand(), LI->getType(), MaybeAlign(LI->getAlignment()), - DL, CtxI, DT, TLI); + LI->getPointerOperand(), LI->getType(), MaybeAlign(LI->getAlign()), DL, + CtxI, DT, TLI); } case Instruction::Call: { auto *CI = cast(Inst); @@ -4975,14 +4977,6 @@ static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly, if (ConsiderFlags && Op->hasPoisonGeneratingFlags()) return true; - // TODO: this should really be under the ConsiderFlags block, but currently - // these are not dropped by dropPoisonGeneratingFlags - if (const auto *FP = dyn_cast(Op)) { - auto FMF = FP->getFastMathFlags(); - if (FMF.noNaNs() || FMF.noInfs()) - return true; - } - unsigned Opcode = Op->getOpcode(); // Check whether opcode is a poison/undef-generating operation diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 41fb0b9008be..e3bf41c9721b 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -733,6 +733,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(x); KEYWORD(blockaddress); KEYWORD(dso_local_equivalent); + KEYWORD(no_cfi); // Metadata types. KEYWORD(distinct); @@ -773,6 +774,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(noUnwind); KEYWORD(mayThrow); KEYWORD(hasUnknownCall); + KEYWORD(mustBeUnreachable); KEYWORD(calls); KEYWORD(callee); KEYWORD(params); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 5feabd876e3a..35c615522fe2 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -152,28 +152,28 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) { FnAttrs.removeAttribute(Attribute::Alignment); } - AS = AS.addFnAttributes(Context, AttributeSet::get(Context, FnAttrs)); + AS = AS.addFnAttributes(Context, FnAttrs); Fn->setAttributes(AS); } else if (CallInst *CI = dyn_cast(V)) { AttributeList AS = CI->getAttributes(); AttrBuilder FnAttrs(AS.getFnAttrs()); AS = AS.removeFnAttributes(Context); FnAttrs.merge(B); - AS = AS.addFnAttributes(Context, AttributeSet::get(Context, FnAttrs)); + AS = AS.addFnAttributes(Context, FnAttrs); CI->setAttributes(AS); } else if (InvokeInst *II = dyn_cast(V)) { AttributeList AS = II->getAttributes(); AttrBuilder FnAttrs(AS.getFnAttrs()); AS = AS.removeFnAttributes(Context); FnAttrs.merge(B); - AS = AS.addFnAttributes(Context, AttributeSet::get(Context, FnAttrs)); + AS = AS.addFnAttributes(Context, FnAttrs); II->setAttributes(AS); } else if (CallBrInst *CBI = dyn_cast(V)) { AttributeList AS = CBI->getAttributes(); AttrBuilder FnAttrs(AS.getFnAttrs()); AS = AS.removeFnAttributes(Context); FnAttrs.merge(B); - AS = AS.addFnAttributes(Context, AttributeSet::get(Context, FnAttrs)); + AS = AS.addFnAttributes(Context, FnAttrs); CBI->setAttributes(AS); } else if (auto *GV = dyn_cast(V)) { AttrBuilder Attrs(GV->getAttributes()); @@ -1306,7 +1306,8 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B, unsigned MinValue, MaxValue; if (parseVScaleRangeArguments(MinValue, MaxValue)) return true; - B.addVScaleRangeAttr(MinValue, MaxValue); + B.addVScaleRangeAttr(MinValue, + MaxValue > 0 ? MaxValue : Optional()); return false; } case Attribute::Dereferenceable: { @@ -3287,6 +3288,20 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) { return false; } + case lltok::kw_no_cfi: { + // ValID ::= 'no_cfi' @foo + Lex.Lex(); + + if (parseValID(ID, PFS)) + return true; + + if (ID.Kind != ValID::t_GlobalID && ID.Kind != ValID::t_GlobalName) + return error(ID.Loc, "expected global value name in no_cfi"); + + ID.NoCFI = true; + return false; + } + case lltok::kw_trunc: case lltok::kw_zext: case lltok::kw_sext: @@ -5267,9 +5282,13 @@ bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V, } case ValID::t_GlobalName: V = getGlobalVal(ID.StrVal, Ty, ID.Loc); + if (V && ID.NoCFI) + V = NoCFIValue::get(cast(V)); return V == nullptr; case ValID::t_GlobalID: V = getGlobalVal(ID.UIntVal, Ty, ID.Loc); + if (V && ID.NoCFI) + V = NoCFIValue::get(cast(V)); return V == nullptr; case ValID::t_APSInt: if (!Ty->isIntegerTy()) @@ -8533,6 +8552,7 @@ bool LLParser::parseFlag(unsigned &Val) { /// [',' 'noUnwind' ':' Flag]? ')' /// [',' 'mayThrow' ':' Flag]? ')' /// [',' 'hasUnknownCall' ':' Flag]? ')' +/// [',' 'mustBeUnreachable' ':' Flag]? ')' bool LLParser::parseOptionalFFlags(FunctionSummary::FFlags &FFlags) { assert(Lex.getKind() == lltok::kw_funcFlags); @@ -8599,6 +8619,12 @@ bool LLParser::parseOptionalFFlags(FunctionSummary::FFlags &FFlags) { return true; FFlags.HasUnknownCall = Val; break; + case lltok::kw_mustBeUnreachable: + Lex.Lex(); + if (parseToken(lltok::colon, "expected ':'") || parseFlag(Val)) + return true; + FFlags.MustBeUnreachable = Val; + break; default: return error(Lex.getLoc(), "expected function flag type"); } diff --git a/llvm/lib/BinaryFormat/AMDGPUMetadataVerifier.cpp b/llvm/lib/BinaryFormat/AMDGPUMetadataVerifier.cpp index cd1d872cc219..284e469a1d2f 100644 --- a/llvm/lib/BinaryFormat/AMDGPUMetadataVerifier.cpp +++ b/llvm/lib/BinaryFormat/AMDGPUMetadataVerifier.cpp @@ -57,11 +57,7 @@ bool MetadataVerifier::verifyArray( auto &Array = Node.getArray(); if (Size && Array.size() != *Size) return false; - for (auto &Item : Array) - if (!verifyNode(Item)) - return false; - - return true; + return llvm::all_of(Array, verifyNode); } bool MetadataVerifier::verifyEntry( diff --git a/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp b/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp index d7bcb0d7f575..a36b256c29b6 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp @@ -107,9 +107,9 @@ static Optional GetCodeName(unsigned CodeID, unsigned BlockID, // Check to see if we have a blockinfo record for this record, with a name. if (const BitstreamBlockInfo::BlockInfo *Info = BlockInfo.getBlockInfo(BlockID)) { - for (unsigned i = 0, e = Info->RecordNames.size(); i != e; ++i) - if (Info->RecordNames[i].first == CodeID) - return Info->RecordNames[i].second.c_str(); + for (const std::pair &RN : Info->RecordNames) + if (RN.first == CodeID) + return RN.second.c_str(); } if (CurStreamType != LLVMIRBitstream) @@ -219,6 +219,7 @@ static Optional GetCodeName(unsigned CodeID, unsigned BlockID, STRINGIFY_CODE(CST_CODE, CE_SHUFVEC_EX) STRINGIFY_CODE(CST_CODE, CE_UNOP) STRINGIFY_CODE(CST_CODE, DSO_LOCAL_EQUIVALENT) + STRINGIFY_CODE(CST_CODE, NO_CFI_VALUE) case bitc::CST_CODE_BLOCKADDRESS: return "CST_CODE_BLOCKADDRESS"; STRINGIFY_CODE(CST_CODE, DATA) @@ -646,16 +647,14 @@ void BitcodeAnalyzer::printStats(BCDumpOptions O, // Emit per-block stats. O.OS << "Per-block Summary:\n"; - for (std::map::iterator I = BlockIDStats.begin(), - E = BlockIDStats.end(); - I != E; ++I) { - O.OS << " Block ID #" << I->first; + for (const auto &Stat : BlockIDStats) { + O.OS << " Block ID #" << Stat.first; if (Optional BlockName = - GetBlockName(I->first, BlockInfo, CurStreamType)) + GetBlockName(Stat.first, BlockInfo, CurStreamType)) O.OS << " (" << *BlockName << ")"; O.OS << ":\n"; - const PerBlockIDStats &Stats = I->second; + const PerBlockIDStats &Stats = Stat.second; O.OS << " Num Instances: " << Stats.NumInstances << "\n"; O.OS << " Total Size: "; printSize(O.OS, Stats.NumBits); @@ -694,8 +693,8 @@ void BitcodeAnalyzer::printStats(BCDumpOptions O, O.OS << "\tRecord Histogram:\n"; O.OS << "\t\t Count # Bits b/Rec % Abv Record Kind\n"; - for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) { - const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second]; + for (const auto &FreqPair : FreqPairs) { + const PerRecordStats &RecStats = Stats.CodeFreq[FreqPair.second]; O.OS << format("\t\t%7d %9lu", RecStats.NumInstances, (unsigned long)RecStats.TotalBits); @@ -714,10 +713,10 @@ void BitcodeAnalyzer::printStats(BCDumpOptions O, O.OS << " "; if (Optional CodeName = GetCodeName( - FreqPairs[i].second, I->first, BlockInfo, CurStreamType)) + FreqPair.second, Stat.first, BlockInfo, CurStreamType)) O.OS << *CodeName << "\n"; else - O.OS << "UnknownCode" << FreqPairs[i].second << "\n"; + O.OS << "UnknownCode" << FreqPair.second << "\n"; } O.OS << "\n"; } diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 993cb1de8c02..f5a878f8788a 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -488,6 +488,7 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer { BitcodeReaderValueList ValueList; Optional MDLoader; std::vector ComdatList; + DenseSet ImplicitComdatObjects; SmallVector InstructionList; std::vector> GlobalInits; @@ -932,6 +933,7 @@ static FunctionSummary::FFlags getDecodedFFlags(uint64_t RawFlags) { Flags.NoUnwind = (RawFlags >> 6) & 0x1; Flags.MayThrow = (RawFlags >> 7) & 0x1; Flags.HasUnknownCall = (RawFlags >> 8) & 0x1; + Flags.MustBeUnreachable = (RawFlags >> 9) & 0x1; return Flags; } @@ -2037,14 +2039,8 @@ Expected BitcodeReader::recordValue(SmallVectorImpl &Record, return error("Invalid value name"); V->setName(NameStr); auto *GO = dyn_cast(V); - if (GO) { - if (GO->getComdat() == reinterpret_cast(1)) { - if (TT.supportsCOMDAT()) - GO->setComdat(TheModule->getOrInsertComdat(V->getName())); - else - GO->setComdat(nullptr); - } - } + if (GO && ImplicitComdatObjects.contains(GO) && TT.supportsCOMDAT()) + GO->setComdat(TheModule->getOrInsertComdat(V->getName())); return V; } @@ -2942,6 +2938,19 @@ Error BitcodeReader::parseConstants() { V = DSOLocalEquivalent::get(GV); break; } + case bitc::CST_CODE_NO_CFI_VALUE: { + if (Record.size() < 2) + return error("Invalid record"); + Type *GVTy = getTypeByID(Record[0]); + if (!GVTy) + return error("Invalid record"); + GlobalValue *GV = dyn_cast_or_null( + ValueList.getConstantFwdRef(Record[1], GVTy)); + if (!GV) + return error("Invalid record"); + V = NoCFIValue::get(GV); + break; + } } ValueList.assignValue(V, NextCstNo); @@ -3292,7 +3301,7 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef Record) { NewGV->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { - NewGV->setComdat(reinterpret_cast(1)); + ImplicitComdatObjects.insert(NewGV); } if (Record.size() > 12) { @@ -3426,7 +3435,7 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef Record) { Func->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { - Func->setComdat(reinterpret_cast(1)); + ImplicitComdatObjects.insert(Func); } if (Record.size() > 13) @@ -6733,10 +6742,10 @@ llvm::getBitcodeFileContents(MemoryBufferRef Buffer) { // not have its own string table. A bitcode file may have multiple // string tables if it was created by binary concatenation, for example // with "llvm-cat -b". - for (auto I = F.Mods.rbegin(), E = F.Mods.rend(); I != E; ++I) { - if (!I->Strtab.empty()) + for (BitcodeModule &I : llvm::reverse(F.Mods)) { + if (!I.Strtab.empty()) break; - I->Strtab = *Strtab; + I.Strtab = *Strtab; } // Similarly, the string table is used by every preceding symbol table; // normally there will be just one unless the bitcode file was created diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index e2354c40844a..dc06bc10cf95 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -833,8 +833,7 @@ void ModuleBitcodeWriter::writeAttributeTable() { Stream.EnterSubblock(bitc::PARAMATTR_BLOCK_ID, 3); SmallVector Record; - for (unsigned i = 0, e = Attrs.size(); i != e; ++i) { - AttributeList AL = Attrs[i]; + for (const AttributeList &AL : Attrs) { for (unsigned i : AL.indexes()) { AttributeSet AS = AL.getAttributes(i); if (AS.hasAttributes()) @@ -1067,6 +1066,7 @@ static uint64_t getEncodedFFlags(FunctionSummary::FFlags Flags) { RawFlags |= (Flags.NoUnwind << 6); RawFlags |= (Flags.MayThrow << 7); RawFlags |= (Flags.HasUnknownCall << 8); + RawFlags |= (Flags.MustBeUnreachable << 9); return RawFlags; } @@ -2657,6 +2657,10 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, Code = bitc::CST_CODE_DSO_LOCAL_EQUIVALENT; Record.push_back(VE.getTypeID(Equiv->getGlobalValue()->getType())); Record.push_back(VE.getValueID(Equiv->getGlobalValue())); + } else if (const auto *NC = dyn_cast(C)) { + Code = bitc::CST_CODE_NO_CFI_VALUE; + Record.push_back(VE.getTypeID(NC->getGlobalValue()->getType())); + Record.push_back(VE.getValueID(NC->getGlobalValue())); } else { #ifndef NDEBUG C->dump(); diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp index 07e0708e68c3..df4f1a1873d7 100644 --- a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp +++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -310,8 +310,7 @@ static UseListOrderStack predictUseListOrder(const Module &M) { // We want to visit the functions backward now so we can list function-local // constants in the last Function they're used in. Module-level constants // have already been visited above. - for (auto I = M.rbegin(), E = M.rend(); I != E; ++I) { - const Function &F = *I; + for (const Function &F : llvm::reverse(M)) { if (F.isDeclaration()) continue; for (const BasicBlock &BB : F) @@ -541,9 +540,8 @@ void ValueEnumerator::print(raw_ostream &OS, const ValueMapType &Map, const char *Name) const { OS << "Map Name: " << Name << "\n"; OS << "Size: " << Map.size() << "\n"; - for (ValueMapType::const_iterator I = Map.begin(), - E = Map.end(); I != E; ++I) { - const Value *V = I->first; + for (const auto &I : Map) { + const Value *V = I.first; if (V->hasName()) OS << "Value: " << V->getName(); else @@ -569,10 +567,10 @@ void ValueEnumerator::print(raw_ostream &OS, const MetadataMapType &Map, const char *Name) const { OS << "Map Name: " << Name << "\n"; OS << "Size: " << Map.size() << "\n"; - for (auto I = Map.begin(), E = Map.end(); I != E; ++I) { - const Metadata *MD = I->first; - OS << "Metadata: slot = " << I->second.ID << "\n"; - OS << "Metadata: function = " << I->second.F << "\n"; + for (const auto &I : Map) { + const Metadata *MD = I.first; + OS << "Metadata: slot = " << I.second.ID << "\n"; + OS << "Metadata: function = " << I.second.F << "\n"; MD->print(OS); OS << "\n"; } diff --git a/llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp b/llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp index 5984063627b0..5c64622c7245 100644 --- a/llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp +++ b/llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp @@ -561,8 +561,7 @@ bool AggressiveAntiDepBreaker::FindSuitableFreeRegisters( << ":\n"); std::map RenameRegisterMap; unsigned SuperReg = 0; - for (unsigned i = 0, e = Regs.size(); i != e; ++i) { - unsigned Reg = Regs[i]; + for (unsigned Reg : Regs) { if ((SuperReg == 0) || TRI->isSuperRegister(SuperReg, Reg)) SuperReg = Reg; @@ -584,8 +583,7 @@ bool AggressiveAntiDepBreaker::FindSuitableFreeRegisters( } // All group registers should be a subreg of SuperReg. - for (unsigned i = 0, e = Regs.size(); i != e; ++i) { - unsigned Reg = Regs[i]; + for (unsigned Reg : Regs) { if (Reg == SuperReg) continue; bool IsSub = TRI->isSubRegister(SuperReg, Reg); // FIXME: remove this once PR18663 has been properly fixed. For now, @@ -646,8 +644,7 @@ bool AggressiveAntiDepBreaker::FindSuitableFreeRegisters( // For each referenced group register (which must be a SuperReg or // a subregister of SuperReg), find the corresponding subregister // of NewSuperReg and make sure it is free to be renamed. - for (unsigned i = 0, e = Regs.size(); i != e; ++i) { - unsigned Reg = Regs[i]; + for (unsigned Reg : Regs) { unsigned NewReg = 0; if (Reg == SuperReg) { NewReg = NewSuperReg; diff --git a/llvm/lib/CodeGen/Analysis.cpp b/llvm/lib/CodeGen/Analysis.cpp index 7d8a73e12d3a..7e68e5e22879 100644 --- a/llvm/lib/CodeGen/Analysis.cpp +++ b/llvm/lib/CodeGen/Analysis.cpp @@ -712,8 +712,8 @@ bool llvm::returnTypeIsEligibleForTailCall(const Function *F, // The manipulations performed when we're looking through an insertvalue or // an extractvalue would happen at the front of the RetPath list, so since // we have to copy it anyway it's more efficient to create a reversed copy. - SmallVector TmpRetPath(RetPath.rbegin(), RetPath.rend()); - SmallVector TmpCallPath(CallPath.rbegin(), CallPath.rend()); + SmallVector TmpRetPath(llvm::reverse(RetPath)); + SmallVector TmpCallPath(llvm::reverse(CallPath)); // Finally, we can check whether the value produced by the tail call at this // index is compatible with the value we return. diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 828cb760b82e..533f20535655 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -180,7 +180,7 @@ Align AsmPrinter::getGVAlignment(const GlobalObject *GV, const DataLayout &DL, Alignment = InAlign; // If the GV has a specified alignment, take it into account. - const MaybeAlign GVAlign(GV->getAlignment()); + const MaybeAlign GVAlign(GV->getAlign()); if (!GVAlign) return Alignment; @@ -288,7 +288,11 @@ bool AsmPrinter::doInitialization(Module &M) { // use the directive, where it would need the same conditionalization // anyway. const Triple &Target = TM.getTargetTriple(); - OutStreamer->emitVersionForTarget(Target, M.getSDKVersion()); + Triple TVT(M.getDarwinTargetVariantTriple()); + OutStreamer->emitVersionForTarget( + Target, M.getSDKVersion(), + M.getDarwinTargetVariantTriple().empty() ? nullptr : &TVT, + M.getDarwinTargetVariantSDKVersion()); // Allow the target to emit any magic that it wants at the start of the file. emitStartOfAsmFile(M); @@ -1856,6 +1860,17 @@ bool AsmPrinter::doFinalization(Module &M) { continue; OutStreamer->emitSymbolAttribute(getSymbol(&GO), MCSA_WeakReference); } + if (shouldEmitWeakSwiftAsyncExtendedFramePointerFlags()) { + auto SymbolName = "swift_async_extendedFramePointerFlags"; + auto Global = M.getGlobalVariable(SymbolName); + if (!Global) { + auto Int8PtrTy = Type::getInt8PtrTy(M.getContext()); + Global = new GlobalVariable(M, Int8PtrTy, false, + GlobalValue::ExternalWeakLinkage, nullptr, + SymbolName); + OutStreamer->emitSymbolAttribute(getSymbol(Global), MCSA_WeakReference); + } + } } // Print aliases in topological order, that is, for each alias a = b, @@ -2502,6 +2517,9 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { if (const auto *Equiv = dyn_cast(CV)) return getObjFileLowering().lowerDSOLocalEquivalent(Equiv, TM); + if (const NoCFIValue *NC = dyn_cast(CV)) + return MCSymbolRefExpr::create(getSymbol(NC->getGlobalValue()), Ctx); + const ConstantExpr *CE = dyn_cast(CV); if (!CE) { llvm_unreachable("Unknown constant value to lower!"); diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 85ff84484ced..d621108408f0 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -611,8 +611,8 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) { void CodeViewDebug::beginModule(Module *M) { // If module doesn't have named metadata anchors or COFF debug section // is not available, skip any debug info related stuff. - if (!M->getNamedMetadata("llvm.dbg.cu") || - !Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) { + NamedMDNode *CUs = M->getNamedMetadata("llvm.dbg.cu"); + if (!CUs || !Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) { Asm = nullptr; return; } @@ -622,7 +622,6 @@ void CodeViewDebug::beginModule(Module *M) { TheCPU = mapArchToCVCPUType(Triple(M->getTargetTriple()).getArch()); // Get the current source language. - NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); const MDNode *Node = *CUs->operands().begin(); const auto *CU = cast(Node); @@ -650,6 +649,7 @@ void CodeViewDebug::endModule() { switchToDebugSectionForSymbol(nullptr); MCSymbol *CompilerInfo = beginCVSubsection(DebugSubsectionKind::Symbols); + emitObjName(); emitCompilerInformation(); endCVSubsection(CompilerInfo); @@ -785,6 +785,29 @@ void CodeViewDebug::emitTypeGlobalHashes() { } } +void CodeViewDebug::emitObjName() { + MCSymbol *CompilerEnd = beginSymbolRecord(SymbolKind::S_OBJNAME); + + StringRef PathRef(Asm->TM.Options.ObjectFilenameForDebug); + llvm::SmallString<256> PathStore(PathRef); + + if (PathRef.empty() || PathRef == "-") { + // Don't emit the filename if we're writing to stdout or to /dev/null. + PathRef = {}; + } else { + llvm::sys::path::remove_dots(PathStore, /*remove_dot_dot=*/true); + PathRef = PathStore; + } + + OS.AddComment("Signature"); + OS.emitIntValue(0, 4); + + OS.AddComment("Object name"); + emitNullTerminatedSymbolName(OS, PathRef); + + endSymbolRecord(CompilerEnd); +} + namespace { struct Version { int Part[4]; diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index 6f88e15ee8fe..d1fc3cdccb20 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -302,6 +302,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void emitTypeGlobalHashes(); + void emitObjName(); + void emitCompilerInformation(); void emitBuildInfo(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 0d2736178f0f..9b73f0ab2f05 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -779,7 +779,7 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); auto AddEntry = [&](const DbgValueLocEntry &Entry, - DIExpressionCursor &Cursor) { + DIExpressionCursor &Cursor) { if (Entry.isLocation()) { if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Entry.getLoc().getReg())) @@ -788,11 +788,19 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, // If there is an expression, emit raw unsigned bytes. DwarfExpr.addUnsignedConstant(Entry.getInt()); } else if (Entry.isConstantFP()) { + // DwarfExpression does not support arguments wider than 64 bits + // (see PR52584). + // TODO: Consider chunking expressions containing overly wide + // arguments into separate pointer-sized fragment expressions. APInt RawBytes = Entry.getConstantFP()->getValueAPF().bitcastToAPInt(); - DwarfExpr.addUnsignedConstant(RawBytes); + if (RawBytes.getBitWidth() > 64) + return false; + DwarfExpr.addUnsignedConstant(RawBytes.getZExtValue()); } else if (Entry.isConstantInt()) { APInt RawBytes = Entry.getConstantInt()->getValue(); - DwarfExpr.addUnsignedConstant(RawBytes); + if (RawBytes.getBitWidth() > 64) + return false; + DwarfExpr.addUnsignedConstant(RawBytes.getZExtValue()); } else if (Entry.isTargetIndexLocation()) { TargetIndexLocation Loc = Entry.getTargetIndexLocation(); // TODO TargetIndexLocation is a target-independent. Currently only the @@ -805,11 +813,12 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, return true; }; - DwarfExpr.addExpression( - std::move(Cursor), - [&](unsigned Idx, DIExpressionCursor &Cursor) -> bool { - return AddEntry(DVal->getLocEntries()[Idx], Cursor); - }); + if (!DwarfExpr.addExpression( + std::move(Cursor), + [&](unsigned Idx, DIExpressionCursor &Cursor) -> bool { + return AddEntry(DVal->getLocEntries()[Idx], Cursor); + })) + return VariableDie; // Now attach the location information to the DIE. addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 047676d4c11e..48134f1fd774 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1224,17 +1224,15 @@ void DwarfDebug::beginModule(Module *M) { CU.getOrCreateGlobalVariableDIE(GV, sortGlobalExprs(GVMap[GV])); } - for (auto *Ty : CUNode->getEnumTypes()) { - // The enum types array by design contains pointers to - // MDNodes rather than DIRefs. Unique them here. + for (auto *Ty : CUNode->getEnumTypes()) CU.getOrCreateTypeDIE(cast(Ty)); - } + for (auto *Ty : CUNode->getRetainedTypes()) { // The retained types array by design contains pointers to // MDNodes rather than DIRefs. Unique them here. if (DIType *RT = dyn_cast(Ty)) - // There is no point in force-emitting a forward declaration. - CU.getOrCreateTypeDIE(RT); + // There is no point in force-emitting a forward declaration. + CU.getOrCreateTypeDIE(RT); } // Emit imported_modules last so that the relevant context is already // available. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index 6409c39e7849..37407c98e75f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -463,15 +463,14 @@ static bool isMemoryLocation(DIExpressionCursor ExprCursor) { return true; } -void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, - unsigned FragmentOffsetInBits) { +void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor) { addExpression(std::move(ExprCursor), [](unsigned Idx, DIExpressionCursor &Cursor) -> bool { llvm_unreachable("unhandled opcode found in expression"); }); } -void DwarfExpression::addExpression( +bool DwarfExpression::addExpression( DIExpressionCursor &&ExprCursor, llvm::function_ref InsertArg) { // Entry values can currently only cover the initial register location, @@ -496,7 +495,7 @@ void DwarfExpression::addExpression( case dwarf::DW_OP_LLVM_arg: if (!InsertArg(Op->getArg(0), ExprCursor)) { LocationKind = Unknown; - return; + return false; } break; case dwarf::DW_OP_LLVM_fragment: { @@ -527,7 +526,7 @@ void DwarfExpression::addExpression( setSubRegisterPiece(0, 0); // Reset the location description kind. LocationKind = Unknown; - return; + return true; } case dwarf::DW_OP_plus_uconst: assert(!isRegisterLocation()); @@ -630,6 +629,8 @@ void DwarfExpression::addExpression( if (isImplicitLocation() && !isParameterValue()) // Turn this into an implicit location description. addStackValue(); + + return true; } /// add masking operations to stencil out a subregister. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h index 513e9072309e..e605fe2f7d39 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -340,16 +340,17 @@ public: /// create one if necessary. unsigned getOrCreateBaseType(unsigned BitSize, dwarf::TypeKind Encoding); + /// Emit all remaining operations in the DIExpressionCursor. The + /// cursor must not contain any DW_OP_LLVM_arg operations. + void addExpression(DIExpressionCursor &&Expr); + /// Emit all remaining operations in the DIExpressionCursor. - /// - /// \param FragmentOffsetInBits If this is one fragment out of multiple - /// locations, this is the offset of the - /// fragment inside the entire variable. - void addExpression(DIExpressionCursor &&Expr, - unsigned FragmentOffsetInBits = 0); - void - addExpression(DIExpressionCursor &&Expr, - llvm::function_ref InsertArg); + /// DW_OP_LLVM_arg operations are resolved by calling (\p InsertArg). + // + /// \return false if any call to (\p InsertArg) returns false. + bool addExpression( + DIExpressionCursor &&Expr, + llvm::function_ref InsertArg); /// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to /// the fragment described by \c Expr. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 976e35905144..6b6d63f14f87 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -536,6 +536,18 @@ void DwarfUnit::addThrownTypes(DIE &Die, DINodeArray ThrownTypes) { } } +void DwarfUnit::addAccess(DIE &Die, DINode::DIFlags Flags) { + if ((Flags & DINode::FlagAccessibility) == DINode::FlagProtected) + addUInt(Die, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, + dwarf::DW_ACCESS_protected); + else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPrivate) + addUInt(Die, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, + dwarf::DW_ACCESS_private); + else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPublic) + addUInt(Die, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, + dwarf::DW_ACCESS_public); +} + DIE *DwarfUnit::getOrCreateContextDIE(const DIScope *Context) { if (!Context || isa(Context)) return &getUnitDie(); @@ -842,13 +854,17 @@ void DwarfUnit::addAnnotation(DIE &Buffer, DINodeArray Annotations) { for (const Metadata *Annotation : Annotations->operands()) { const MDNode *MD = cast(Annotation); const MDString *Name = cast(MD->getOperand(0)); - - // Currently, only MDString is supported with btf_decl_tag attribute. - const MDString *Value = cast(MD->getOperand(1)); + const auto &Value = MD->getOperand(1); DIE &AnnotationDie = createAndAddDIE(dwarf::DW_TAG_LLVM_annotation, Buffer); addString(AnnotationDie, dwarf::DW_AT_name, Name->getString()); - addString(AnnotationDie, dwarf::DW_AT_const_value, Value->getString()); + if (const auto *Data = dyn_cast(Value)) + addString(AnnotationDie, dwarf::DW_AT_const_value, Data->getString()); + else if (const auto *Data = dyn_cast(Value)) + addConstantValue(AnnotationDie, Data->getValue()->getUniqueInteger(), + /*Unsigned=*/true); + else + assert(false && "Unsupported annotation value type"); } } @@ -1007,6 +1023,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { if (CTy->isForwardDecl()) addFlag(Buffer, dwarf::DW_AT_declaration); + // Add accessibility info if available. + addAccess(Buffer, CTy->getFlags()); + // Add source line info if available. if (!CTy->isForwardDecl()) addSourceLine(Buffer, CTy); @@ -1308,15 +1327,7 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, if (SP->isNoReturn()) addFlag(SPDie, dwarf::DW_AT_noreturn); - if (SP->isProtected()) - addUInt(SPDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, - dwarf::DW_ACCESS_protected); - else if (SP->isPrivate()) - addUInt(SPDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, - dwarf::DW_ACCESS_private); - else if (SP->isPublic()) - addUInt(SPDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, - dwarf::DW_ACCESS_public); + addAccess(SPDie, SP->getFlags()); if (SP->isExplicit()) addFlag(SPDie, dwarf::DW_AT_explicit); @@ -1666,16 +1677,8 @@ DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { } } - if (DT->isProtected()) - addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, - dwarf::DW_ACCESS_protected); - else if (DT->isPrivate()) - addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, - dwarf::DW_ACCESS_private); - // Otherwise C++ member and base classes are considered public. - else if (DT->isPublic()) - addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, - dwarf::DW_ACCESS_public); + addAccess(MemberDie, DT->getFlags()); + if (DT->isVirtual()) addUInt(MemberDie, dwarf::DW_AT_virtuality, dwarf::DW_FORM_data1, dwarf::DW_VIRTUALITY_virtual); @@ -1717,15 +1720,7 @@ DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) { // FIXME: We could omit private if the parent is a class_type, and // public if the parent is something else. - if (DT->isProtected()) - addUInt(StaticMemberDIE, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, - dwarf::DW_ACCESS_protected); - else if (DT->isPrivate()) - addUInt(StaticMemberDIE, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, - dwarf::DW_ACCESS_private); - else if (DT->isPublic()) - addUInt(StaticMemberDIE, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1, - dwarf::DW_ACCESS_public); + addAccess(StaticMemberDIE, DT->getFlags()); if (const ConstantInt *CI = dyn_cast_or_null(DT->getConstant())) addConstantValue(StaticMemberDIE, CI, Ty); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index 8140279adaef..54b0079dd7ce 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -226,6 +226,9 @@ public: /// Add thrown types. void addThrownTypes(DIE &Die, DINodeArray ThrownTypes); + /// Add the accessibility attribute. + void addAccess(DIE &Die, DINode::DIFlags Flags); + /// Add a new type attribute to the specified entity. /// /// This takes and attribute parameter because DW_AT_friend attributes are diff --git a/llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp index a9fb31d42679..3ade262d9af2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp @@ -112,16 +112,12 @@ void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, EmitCamlGlobal(M, AP, "frametable"); int NumDescriptors = 0; - for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), - IE = Info.funcinfo_end(); - I != IE; ++I) { - GCFunctionInfo &FI = **I; - if (FI.getStrategy().getName() != getStrategy().getName()) + for (std::unique_ptr &FI : + llvm::make_range(Info.funcinfo_begin(), Info.funcinfo_end())) { + if (FI->getStrategy().getName() != getStrategy().getName()) // this function is managed by some other GC continue; - for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { - NumDescriptors++; - } + NumDescriptors += FI->size(); } if (NumDescriptors >= 1 << 16) { @@ -131,35 +127,34 @@ void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, AP.emitInt16(NumDescriptors); AP.emitAlignment(IntPtrSize == 4 ? Align(4) : Align(8)); - for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), - IE = Info.funcinfo_end(); - I != IE; ++I) { - GCFunctionInfo &FI = **I; - if (FI.getStrategy().getName() != getStrategy().getName()) + for (std::unique_ptr &FI : + llvm::make_range(Info.funcinfo_begin(), Info.funcinfo_end())) { + if (FI->getStrategy().getName() != getStrategy().getName()) // this function is managed by some other GC continue; - uint64_t FrameSize = FI.getFrameSize(); + uint64_t FrameSize = FI->getFrameSize(); if (FrameSize >= 1 << 16) { // Very rude! - report_fatal_error("Function '" + FI.getFunction().getName() + + report_fatal_error("Function '" + FI->getFunction().getName() + "' is too large for the ocaml GC! " "Frame size " + Twine(FrameSize) + ">= 65536.\n" "(" + - Twine(reinterpret_cast(&FI)) + ")"); + Twine(reinterpret_cast(FI.get())) + ")"); } AP.OutStreamer->AddComment("live roots for " + - Twine(FI.getFunction().getName())); + Twine(FI->getFunction().getName())); AP.OutStreamer->AddBlankLine(); - for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { - size_t LiveCount = FI.live_size(J); + for (GCFunctionInfo::iterator J = FI->begin(), JE = FI->end(); J != JE; + ++J) { + size_t LiveCount = FI->live_size(J); if (LiveCount >= 1 << 16) { // Very rude! - report_fatal_error("Function '" + FI.getFunction().getName() + + report_fatal_error("Function '" + FI->getFunction().getName() + "' is too large for the ocaml GC! " "Live root count " + Twine(LiveCount) + " >= 65536."); @@ -169,8 +164,8 @@ void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, AP.emitInt16(FrameSize); AP.emitInt16(LiveCount); - for (GCFunctionInfo::live_iterator K = FI.live_begin(J), - KE = FI.live_end(J); + for (GCFunctionInfo::live_iterator K = FI->live_begin(J), + KE = FI->live_end(J); K != KE; ++K) { if (K->StackOffset >= 1 << 16) { // Very rude! diff --git a/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp index 9e6f1a537de3..bab187f46535 100644 --- a/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp @@ -47,7 +47,6 @@ void PseudoProbeHandler::emitPseudoProbe(uint64_t Guid, uint64_t Index, InlinedAt = InlinedAt->getInlinedAt(); } - SmallVector InlineStack(ReversedInlineStack.rbegin(), - ReversedInlineStack.rend()); + SmallVector InlineStack(llvm::reverse(ReversedInlineStack)); Asm->OutStreamer->emitPseudoProbe(Guid, Index, Type, Attr, InlineStack); } diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp index 64dadc82b48b..0ff67f7ca00a 100644 --- a/llvm/lib/CodeGen/BranchFolding.cpp +++ b/llvm/lib/CodeGen/BranchFolding.cpp @@ -1125,8 +1125,8 @@ bool BranchFolder::TailMergeBlocks(MachineFunction &MF) { // If this is a large problem, avoid visiting the same basic blocks multiple // times. if (MergePotentials.size() == TailMergeThreshold) - for (unsigned i = 0, e = MergePotentials.size(); i != e; ++i) - TriedMerging.insert(MergePotentials[i].getBlock()); + for (MergePotentialsElt &Elt : MergePotentials) + TriedMerging.insert(Elt.getBlock()); if (MergePotentials.size() >= 2) MadeChange |= TryTailMergeBlocks(IBB, PredBB, MinCommonTailLength); diff --git a/llvm/lib/CodeGen/CalcSpillWeights.cpp b/llvm/lib/CodeGen/CalcSpillWeights.cpp index 863a0e1e0b56..5f9982cd155d 100644 --- a/llvm/lib/CodeGen/CalcSpillWeights.cpp +++ b/llvm/lib/CodeGen/CalcSpillWeights.cpp @@ -15,13 +15,13 @@ #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/StackMaps.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGen/VirtRegMap.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/CodeGen/StackMaps.h" #include #include @@ -35,7 +35,7 @@ void VirtRegAuxInfo::calculateSpillWeightsAndHints() { MachineRegisterInfo &MRI = MF.getRegInfo(); for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { - unsigned Reg = Register::index2VirtReg(I); + Register Reg = Register::index2VirtReg(I); if (MRI.reg_nodbg_empty(Reg)) continue; calculateSpillWeightAndHint(LIS.getInterval(Reg)); @@ -64,14 +64,14 @@ static Register copyHint(const MachineInstr *MI, unsigned Reg, if (Register::isVirtualRegister(HReg)) return Sub == HSub ? HReg : Register(); - const TargetRegisterClass *rc = MRI.getRegClass(Reg); + const TargetRegisterClass *RC = MRI.getRegClass(Reg); MCRegister CopiedPReg = HSub ? TRI.getSubReg(HReg, HSub) : HReg.asMCReg(); - if (rc->contains(CopiedPReg)) + if (RC->contains(CopiedPReg)) return CopiedPReg; // Check if reg:sub matches so that a super register could be hinted. if (Sub) - return TRI.getMatchingSuperReg(CopiedPReg, Sub, rc); + return TRI.getMatchingSuperReg(CopiedPReg, Sub, RC); return 0; } @@ -80,8 +80,8 @@ static Register copyHint(const MachineInstr *MI, unsigned Reg, static bool isRematerializable(const LiveInterval &LI, const LiveIntervals &LIS, const VirtRegMap &VRM, const TargetInstrInfo &TII) { - unsigned Reg = LI.reg(); - unsigned Original = VRM.getOriginal(Reg); + Register Reg = LI.reg(); + Register Original = VRM.getOriginal(Reg); for (LiveInterval::const_vni_iterator I = LI.vni_begin(), E = LI.vni_end(); I != E; ++I) { const VNInfo *VNI = *I; @@ -183,8 +183,8 @@ float VirtRegAuxInfo::weightCalcHelper(LiveInterval &LI, SlotIndex *Start, bool ShouldUpdateLI = !IsLocalSplitArtifact; if (IsLocalSplitArtifact) { - MachineBasicBlock *localMBB = LIS.getMBBFromIndex(*End); - assert(localMBB == LIS.getMBBFromIndex(*Start) && + MachineBasicBlock *LocalMBB = LIS.getMBBFromIndex(*End); + assert(LocalMBB == LIS.getMBBFromIndex(*Start) && "start and end are expected to be in the same basic block"); // Local split artifact will have 2 additional copy instructions and they @@ -192,8 +192,8 @@ float VirtRegAuxInfo::weightCalcHelper(LiveInterval &LI, SlotIndex *Start, // localLI = COPY other // ... // other = COPY localLI - TotalWeight += LiveIntervals::getSpillWeight(true, false, &MBFI, localMBB); - TotalWeight += LiveIntervals::getSpillWeight(false, true, &MBFI, localMBB); + TotalWeight += LiveIntervals::getSpillWeight(true, false, &MBFI, LocalMBB); + TotalWeight += LiveIntervals::getSpillWeight(false, true, &MBFI, LocalMBB); NumInstr += 2; } diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp index bbdd8aab502e..7c236a9785d8 100644 --- a/llvm/lib/CodeGen/CodeGen.cpp +++ b/llvm/lib/CodeGen/CodeGen.cpp @@ -68,6 +68,8 @@ void llvm::initializeCodeGen(PassRegistry &Registry) { initializeMachineCSEPass(Registry); initializeMachineCombinerPass(Registry); initializeMachineCopyPropagationPass(Registry); + initializeMachineCycleInfoPrinterPassPass(Registry); + initializeMachineCycleInfoWrapperPassPass(Registry); initializeMachineDominatorTreePass(Registry); initializeMachineFunctionPrinterPassPass(Registry); initializeMachineLICMPass(Registry); diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index ac4180c4c3ab..747f4e4fdecc 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -4831,9 +4831,7 @@ static bool IsOperandAMemoryOperand(CallInst *CI, InlineAsm *IA, Value *OpVal, TargetLowering::AsmOperandInfoVector TargetConstraints = TLI.ParseConstraints(F->getParent()->getDataLayout(), &TRI, *CI); - for (unsigned i = 0, e = TargetConstraints.size(); i != e; ++i) { - TargetLowering::AsmOperandInfo &OpInfo = TargetConstraints[i]; - + for (TargetLowering::AsmOperandInfo &OpInfo : TargetConstraints) { // Compute the constraint code and ConstraintType to use. TLI.ComputeConstraintToUse(OpInfo, SDValue()); @@ -5617,9 +5615,7 @@ bool CodeGenPrepare::optimizeInlineAsmInst(CallInst *CS) { TargetLowering::AsmOperandInfoVector TargetConstraints = TLI->ParseConstraints(*DL, TRI, *CS); unsigned ArgNo = 0; - for (unsigned i = 0, e = TargetConstraints.size(); i != e; ++i) { - TargetLowering::AsmOperandInfo &OpInfo = TargetConstraints[i]; - + for (TargetLowering::AsmOperandInfo &OpInfo : TargetConstraints) { // Compute the constraint code and ConstraintType to use. TLI->ComputeConstraintToUse(OpInfo, SDValue()); @@ -6856,8 +6852,7 @@ bool CodeGenPrepare::optimizeSelectInst(SelectInst *SI) { // Use reverse iterator because later select may use the value of the // earlier select, and we need to propagate value through earlier select // to get the PHI operand. - for (auto It = ASI.rbegin(); It != ASI.rend(); ++It) { - SelectInst *SI = *It; + for (SelectInst *SI : llvm::reverse(ASI)) { // The select itself is replaced with a PHI Node. PHINode *PN = PHINode::Create(SI->getType(), 2, "", &EndBlock->front()); PN->takeName(SI); diff --git a/llvm/lib/CodeGen/CriticalAntiDepBreaker.cpp b/llvm/lib/CodeGen/CriticalAntiDepBreaker.cpp index 4e98d49206b5..901409ea9f8f 100644 --- a/llvm/lib/CodeGen/CriticalAntiDepBreaker.cpp +++ b/llvm/lib/CodeGen/CriticalAntiDepBreaker.cpp @@ -405,8 +405,7 @@ findSuitableFreeRegister(RegRefIter RegRefBegin, const TargetRegisterClass *RC, SmallVectorImpl &Forbid) { ArrayRef Order = RegClassInfo.getOrder(RC); - for (unsigned i = 0; i != Order.size(); ++i) { - unsigned NewReg = Order[i]; + for (unsigned NewReg : Order) { // Don't replace a register with itself. if (NewReg == AntiDepReg) continue; // Don't replace a register with one that was recently used to repair diff --git a/llvm/lib/CodeGen/DeadMachineInstructionElim.cpp b/llvm/lib/CodeGen/DeadMachineInstructionElim.cpp index 0bb186a02416..5579152f1ce0 100644 --- a/llvm/lib/CodeGen/DeadMachineInstructionElim.cpp +++ b/llvm/lib/CodeGen/DeadMachineInstructionElim.cpp @@ -142,9 +142,9 @@ bool DeadMachineInstructionElim::eliminateDeadMI(MachineFunction &MF) { if (isDead(&MI)) { LLVM_DEBUG(dbgs() << "DeadMachineInstructionElim: DELETING: " << MI); // It is possible that some DBG_VALUE instructions refer to this - // instruction. They get marked as undef and will be deleted - // in the live debug variable analysis. - MI.eraseFromParentAndMarkDBGValuesForRemoval(); + // instruction. They will be deleted in the live debug variable + // analysis. + MI.eraseFromParent(); AnyChanges = true; ++NumDeletes; continue; diff --git a/llvm/lib/CodeGen/EarlyIfConversion.cpp b/llvm/lib/CodeGen/EarlyIfConversion.cpp index 90883212a275..0b5469b02637 100644 --- a/llvm/lib/CodeGen/EarlyIfConversion.cpp +++ b/llvm/lib/CodeGen/EarlyIfConversion.cpp @@ -210,9 +210,9 @@ bool SSAIfConv::canSpeculateInstrs(MachineBasicBlock *MBB) { // Check all instructions, except the terminators. It is assumed that // terminators never have side effects or define any used register values. - for (MachineBasicBlock::iterator I = MBB->begin(), - E = MBB->getFirstTerminator(); I != E; ++I) { - if (I->isDebugInstr()) + for (MachineInstr &MI : + llvm::make_range(MBB->begin(), MBB->getFirstTerminator())) { + if (MI.isDebugInstr()) continue; if (++InstrCount > BlockInstrLimit && !Stress) { @@ -222,28 +222,28 @@ bool SSAIfConv::canSpeculateInstrs(MachineBasicBlock *MBB) { } // There shouldn't normally be any phis in a single-predecessor block. - if (I->isPHI()) { - LLVM_DEBUG(dbgs() << "Can't hoist: " << *I); + if (MI.isPHI()) { + LLVM_DEBUG(dbgs() << "Can't hoist: " << MI); return false; } // Don't speculate loads. Note that it may be possible and desirable to // speculate GOT or constant pool loads that are guaranteed not to trap, // but we don't support that for now. - if (I->mayLoad()) { - LLVM_DEBUG(dbgs() << "Won't speculate load: " << *I); + if (MI.mayLoad()) { + LLVM_DEBUG(dbgs() << "Won't speculate load: " << MI); return false; } // We never speculate stores, so an AA pointer isn't necessary. bool DontMoveAcrossStore = true; - if (!I->isSafeToMove(nullptr, DontMoveAcrossStore)) { - LLVM_DEBUG(dbgs() << "Can't speculate: " << *I); + if (!MI.isSafeToMove(nullptr, DontMoveAcrossStore)) { + LLVM_DEBUG(dbgs() << "Can't speculate: " << MI); return false; } // Check for any dependencies on Head instructions. - if (!InstrDependenciesAllowIfConv(&(*I))) + if (!InstrDependenciesAllowIfConv(&MI)) return false; } return true; diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index 17094a8e44f8..d061664e8c5d 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -256,7 +256,7 @@ mergeVectorRegsToResultRegs(MachineIRBuilder &B, ArrayRef DstRegs, LLT PartLLT = MRI.getType(SrcRegs[0]); // Deal with v3s16 split into v2s16 - LLT LCMTy = getLCMType(LLTy, PartLLT); + LLT LCMTy = getCoverTy(LLTy, PartLLT); if (LCMTy == LLTy) { // Common case where no padding is needed. assert(DstRegs.size() == 1); @@ -267,21 +267,9 @@ mergeVectorRegsToResultRegs(MachineIRBuilder &B, ArrayRef DstRegs, // widening the original value. Register UnmergeSrcReg; if (LCMTy != PartLLT) { - // e.g. A <3 x s16> value was split to <2 x s16> - // %register_value0:_(<2 x s16>) - // %register_value1:_(<2 x s16>) - // %undef:_(<2 x s16>) = G_IMPLICIT_DEF - // %concat:_<6 x s16>) = G_CONCAT_VECTORS %reg_value0, %reg_value1, %undef - // %dst_reg:_(<3 x s16>), %dead:_(<3 x s16>) = G_UNMERGE_VALUES %concat - const int NumWide = LCMTy.getSizeInBits() / PartLLT.getSizeInBits(); - Register Undef = B.buildUndef(PartLLT).getReg(0); - - // Build vector of undefs. - SmallVector WidenedSrcs(NumWide, Undef); - - // Replace the first sources with the real registers. - std::copy(SrcRegs.begin(), SrcRegs.end(), WidenedSrcs.begin()); - UnmergeSrcReg = B.buildConcatVectors(LCMTy, WidenedSrcs).getReg(0); + assert(DstRegs.size() == 1); + return B.buildDeleteTrailingVectorElements(DstRegs[0], + B.buildMerge(LCMTy, SrcRegs)); } else { // We don't need to widen anything if we're extracting a scalar which was // promoted to a vector e.g. s8 -> v4s8 -> s8 @@ -298,6 +286,8 @@ mergeVectorRegsToResultRegs(MachineIRBuilder &B, ArrayRef DstRegs, for (int I = DstRegs.size(); I != NumDst; ++I) PadDstRegs[I] = MRI.createGenericVirtualRegister(LLTy); + if (PadDstRegs.size() == 1) + return B.buildDeleteTrailingVectorElements(DstRegs[0], UnmergeSrcReg); return B.buildUnmerge(PadDstRegs, UnmergeSrcReg); } @@ -485,7 +475,7 @@ static void buildCopyToRegs(MachineIRBuilder &B, ArrayRef DstRegs, MachineRegisterInfo &MRI = *B.getMRI(); LLT DstTy = MRI.getType(DstRegs[0]); - LLT LCMTy = getLCMType(SrcTy, PartTy); + LLT LCMTy = getCoverTy(SrcTy, PartTy); const unsigned DstSize = DstTy.getSizeInBits(); const unsigned SrcSize = SrcTy.getSizeInBits(); @@ -493,7 +483,7 @@ static void buildCopyToRegs(MachineIRBuilder &B, ArrayRef DstRegs, Register UnmergeSrc = SrcReg; - if (CoveringSize != SrcSize) { + if (!LCMTy.isVector() && CoveringSize != SrcSize) { // For scalars, it's common to be able to use a simple extension. if (SrcTy.isScalar() && DstTy.isScalar()) { CoveringSize = alignTo(SrcSize, DstSize); @@ -510,14 +500,10 @@ static void buildCopyToRegs(MachineIRBuilder &B, ArrayRef DstRegs, } } - // Unmerge to the original registers and pad with dead defs. - SmallVector UnmergeResults(DstRegs.begin(), DstRegs.end()); - for (unsigned Size = DstSize * DstRegs.size(); Size != CoveringSize; - Size += DstSize) { - UnmergeResults.push_back(MRI.createGenericVirtualRegister(DstTy)); - } + if (LCMTy.isVector() && CoveringSize != SrcSize) + UnmergeSrc = B.buildPadVectorWithUndefElements(LCMTy, SrcReg).getReg(0); - B.buildUnmerge(UnmergeResults, UnmergeSrc); + B.buildUnmerge(DstRegs, UnmergeSrc); } bool CallLowering::determineAndHandleAssignments( diff --git a/llvm/lib/CodeGen/GlobalISel/Combiner.cpp b/llvm/lib/CodeGen/GlobalISel/Combiner.cpp index 381c6df5c97a..dd1ef74e8ad0 100644 --- a/llvm/lib/CodeGen/GlobalISel/Combiner.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Combiner.cpp @@ -135,7 +135,7 @@ bool Combiner::combineMachineInstrs(MachineFunction &MF, // Erase dead insts before even adding to the list. if (isTriviallyDead(CurMI, *MRI)) { LLVM_DEBUG(dbgs() << CurMI << "Is dead; erasing.\n"); - CurMI.eraseFromParentAndMarkDBGValuesForRemoval(); + CurMI.eraseFromParent(); continue; } WorkList.deferred_insert(&CurMI); diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 755b3b844570..f7a634dad61a 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1551,8 +1551,8 @@ void CombinerHelper::applyShiftOfShiftedLogic(MachineInstr &MI, Builder.buildInstr(MatchInfo.Logic->getOpcode(), {Dest}, {Shift1, Shift2}); // These were one use so it's safe to remove them. - MatchInfo.Shift2->eraseFromParentAndMarkDBGValuesForRemoval(); - MatchInfo.Logic->eraseFromParentAndMarkDBGValuesForRemoval(); + MatchInfo.Shift2->eraseFromParent(); + MatchInfo.Logic->eraseFromParent(); MI.eraseFromParent(); } diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 87cc60d51bc2..6d415c9c7f90 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -338,9 +338,10 @@ bool IRTranslator::translateCompare(const User &U, MIRBuilder.buildCopy( Res, getOrCreateVReg(*Constant::getAllOnesValue(U.getType()))); else { - assert(CI && "Instruction should be CmpInst"); - MIRBuilder.buildFCmp(Pred, Res, Op0, Op1, - MachineInstr::copyFlagsFromInstruction(*CI)); + uint16_t Flags = 0; + if (CI) + Flags = MachineInstr::copyFlagsFromInstruction(*CI); + MIRBuilder.buildFCmp(Pred, Res, Op0, Op1, Flags); } return true; @@ -3502,7 +3503,7 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { // Get rid of the now empty basic block. EntryBB->removeSuccessor(&NewEntryBB); MF->remove(EntryBB); - MF->DeleteMachineBasicBlock(EntryBB); + MF->deleteMachineBasicBlock(EntryBB); assert(&MF->front() == &NewEntryBB && "New entry wasn't next in the list of basic block!"); diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp index 9b2692486384..b10c9272a508 100644 --- a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp +++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp @@ -163,7 +163,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { // If so, erase it. if (isTriviallyDead(MI, MRI)) { LLVM_DEBUG(dbgs() << "Is dead; erasing.\n"); - MI.eraseFromParentAndMarkDBGValuesForRemoval(); + MI.eraseFromParent(); continue; } @@ -255,8 +255,12 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { MachineInstr *MI = nullptr; if (!MRI.def_empty(VReg)) MI = &*MRI.def_instr_begin(VReg); - else if (!MRI.use_empty(VReg)) + else if (!MRI.use_empty(VReg)) { MI = &*MRI.use_instr_begin(VReg); + // Debug value instruction is permitted to use undefined vregs. + if (MI->isDebugValue()) + continue; + } if (!MI) continue; diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index e09cd26eb0c1..e8a8efd5dad4 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -176,16 +176,18 @@ bool LegalizerHelper::extractParts(Register Reg, LLT RegTy, return true; } + // Perform irregular split. Leftover is last element of RegPieces. if (MainTy.isVector()) { - unsigned EltSize = MainTy.getScalarSizeInBits(); - if (LeftoverSize % EltSize != 0) - return false; - LeftoverTy = LLT::scalarOrVector( - ElementCount::getFixed(LeftoverSize / EltSize), EltSize); - } else { - LeftoverTy = LLT::scalar(LeftoverSize); + SmallVector RegPieces; + extractVectorParts(Reg, MainTy.getNumElements(), RegPieces); + for (unsigned i = 0; i < RegPieces.size() - 1; ++i) + VRegs.push_back(RegPieces[i]); + LeftoverRegs.push_back(RegPieces[RegPieces.size() - 1]); + LeftoverTy = MRI.getType(LeftoverRegs[0]); + return true; } + LeftoverTy = LLT::scalar(LeftoverSize); // For irregular sizes, extract the individual parts. for (unsigned I = 0; I != NumParts; ++I) { Register NewReg = MRI.createGenericVirtualRegister(MainTy); @@ -203,6 +205,44 @@ bool LegalizerHelper::extractParts(Register Reg, LLT RegTy, return true; } +void LegalizerHelper::extractVectorParts(Register Reg, unsigned NumElts, + SmallVectorImpl &VRegs) { + LLT RegTy = MRI.getType(Reg); + assert(RegTy.isVector() && "Expected a vector type"); + + LLT EltTy = RegTy.getElementType(); + LLT NarrowTy = (NumElts == 1) ? EltTy : LLT::fixed_vector(NumElts, EltTy); + unsigned RegNumElts = RegTy.getNumElements(); + unsigned LeftoverNumElts = RegNumElts % NumElts; + unsigned NumNarrowTyPieces = RegNumElts / NumElts; + + // Perfect split without leftover + if (LeftoverNumElts == 0) + return extractParts(Reg, NarrowTy, NumNarrowTyPieces, VRegs); + + // Irregular split. Provide direct access to all elements for artifact + // combiner using unmerge to elements. Then build vectors with NumElts + // elements. Remaining element(s) will be (used to build vector) Leftover. + SmallVector Elts; + extractParts(Reg, EltTy, RegNumElts, Elts); + + unsigned Offset = 0; + // Requested sub-vectors of NarrowTy. + for (unsigned i = 0; i < NumNarrowTyPieces; ++i, Offset += NumElts) { + ArrayRef Pieces(&Elts[Offset], NumElts); + VRegs.push_back(MIRBuilder.buildMerge(NarrowTy, Pieces).getReg(0)); + } + + // Leftover element(s). + if (LeftoverNumElts == 1) { + VRegs.push_back(Elts[Offset]); + } else { + LLT LeftoverTy = LLT::fixed_vector(LeftoverNumElts, EltTy); + ArrayRef Pieces(&Elts[Offset], LeftoverNumElts); + VRegs.push_back(MIRBuilder.buildMerge(LeftoverTy, Pieces).getReg(0)); + } +} + void LegalizerHelper::insertParts(Register DstReg, LLT ResultTy, LLT PartTy, ArrayRef PartRegs, @@ -223,6 +263,15 @@ void LegalizerHelper::insertParts(Register DstReg, return; } + // Merge sub-vectors with different number of elements and insert into DstReg. + if (ResultTy.isVector()) { + assert(LeftoverRegs.size() == 1 && "Expected one leftover register"); + SmallVector AllRegs; + for (auto Reg : concat(PartRegs, LeftoverRegs)) + AllRegs.push_back(Reg); + return mergeMixedSubvectors(DstReg, AllRegs); + } + SmallVector GCDRegs; LLT GCDTy = getGCDType(getGCDType(ResultTy, LeftoverTy), PartTy); for (auto PartReg : concat(PartRegs, LeftoverRegs)) @@ -231,6 +280,30 @@ void LegalizerHelper::insertParts(Register DstReg, buildWidenedRemergeToDst(DstReg, ResultLCMTy, GCDRegs); } +void LegalizerHelper::appendVectorElts(SmallVectorImpl &Elts, + Register Reg) { + LLT Ty = MRI.getType(Reg); + SmallVector RegElts; + extractParts(Reg, Ty.getScalarType(), Ty.getNumElements(), RegElts); + Elts.append(RegElts); +} + +/// Merge \p PartRegs with different types into \p DstReg. +void LegalizerHelper::mergeMixedSubvectors(Register DstReg, + ArrayRef PartRegs) { + SmallVector AllElts; + for (unsigned i = 0; i < PartRegs.size() - 1; ++i) + appendVectorElts(AllElts, PartRegs[i]); + + Register Leftover = PartRegs[PartRegs.size() - 1]; + if (MRI.getType(Leftover).isScalar()) + AllElts.push_back(Leftover); + else + appendVectorElts(AllElts, Leftover); + + MIRBuilder.buildMerge(DstReg, AllElts); +} + /// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs. static void getUnmergeResults(SmallVectorImpl &Regs, const MachineInstr &MI) { @@ -916,8 +989,26 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, return Legalized; } - case TargetOpcode::G_FREEZE: - return reduceOperationWidth(MI, TypeIdx, NarrowTy); + case TargetOpcode::G_FREEZE: { + if (TypeIdx != 0) + return UnableToLegalize; + + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + // Should widen scalar first + if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0) + return UnableToLegalize; + + auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg()); + SmallVector Parts; + for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) { + Parts.push_back( + MIRBuilder.buildFreeze(NarrowTy, Unmerge.getReg(i)).getReg(0)); + } + + MIRBuilder.buildMerge(MI.getOperand(0).getReg(), Parts); + MI.eraseFromParent(); + return Legalized; + } case TargetOpcode::G_ADD: case TargetOpcode::G_SUB: case TargetOpcode::G_SADDO: @@ -1372,37 +1463,17 @@ void LegalizerHelper::moreElementsVectorDst(MachineInstr &MI, LLT WideTy, unsigned OpIdx) { MachineOperand &MO = MI.getOperand(OpIdx); MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt()); - MO.setReg(widenWithUnmerge(WideTy, MO.getReg())); + Register Dst = MO.getReg(); + Register DstExt = MRI.createGenericVirtualRegister(WideTy); + MO.setReg(DstExt); + MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt); } void LegalizerHelper::moreElementsVectorSrc(MachineInstr &MI, LLT MoreTy, unsigned OpIdx) { MachineOperand &MO = MI.getOperand(OpIdx); - - LLT OldTy = MRI.getType(MO.getReg()); - unsigned OldElts = OldTy.getNumElements(); - unsigned NewElts = MoreTy.getNumElements(); - - unsigned NumParts = NewElts / OldElts; - - // Use concat_vectors if the result is a multiple of the number of elements. - if (NumParts * OldElts == NewElts) { - SmallVector Parts; - Parts.push_back(MO.getReg()); - - Register ImpDef = MIRBuilder.buildUndef(OldTy).getReg(0); - for (unsigned I = 1; I != NumParts; ++I) - Parts.push_back(ImpDef); - - auto Concat = MIRBuilder.buildConcatVectors(MoreTy, Parts); - MO.setReg(Concat.getReg(0)); - return; - } - - Register MoreReg = MRI.createGenericVirtualRegister(MoreTy); - Register ImpDef = MIRBuilder.buildUndef(MoreTy).getReg(0); - MIRBuilder.buildInsert(MoreReg, ImpDef, MO.getReg(), 0); - MO.setReg(MoreReg); + SmallVector Regs; + MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0)); } void LegalizerHelper::bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx) { @@ -3558,20 +3629,83 @@ Register LegalizerHelper::getVectorElementPointer(Register VecPtr, LLT VecTy, return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0); } -LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorImplicitDef( - MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy) { - Register DstReg = MI.getOperand(0).getReg(); - LLT DstTy = MRI.getType(DstReg); - LLT LCMTy = getLCMType(DstTy, NarrowTy); +#ifndef NDEBUG +/// Check that all vector operands have same number of elements. Other operands +/// should be listed in NonVecOp. +static bool hasSameNumEltsOnAllVectorOperands( + GenericMachineInstr &MI, MachineRegisterInfo &MRI, + std::initializer_list NonVecOpIndices) { + if (MI.getNumMemOperands() != 0) + return false; - unsigned NumParts = LCMTy.getSizeInBits() / NarrowTy.getSizeInBits(); + LLT VecTy = MRI.getType(MI.getReg(0)); + if (!VecTy.isVector()) + return false; + unsigned NumElts = VecTy.getNumElements(); - auto NewUndef = MIRBuilder.buildUndef(NarrowTy); - SmallVector Parts(NumParts, NewUndef.getReg(0)); + for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) { + MachineOperand &Op = MI.getOperand(OpIdx); + if (!Op.isReg()) { + if (!is_contained(NonVecOpIndices, OpIdx)) + return false; + continue; + } - buildWidenedRemergeToDst(DstReg, LCMTy, Parts); - MI.eraseFromParent(); - return Legalized; + LLT Ty = MRI.getType(Op.getReg()); + if (!Ty.isVector()) { + if (!is_contained(NonVecOpIndices, OpIdx)) + return false; + is_contained(NonVecOpIndices, OpIdx); + continue; + } + + if (Ty.getNumElements() != NumElts) + return false; + } + + return true; +} +#endif + +/// Fill \p DstOps with DstOps that have same number of elements combined as +/// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are +/// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple +/// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements. +static void makeDstOps(SmallVectorImpl &DstOps, LLT Ty, + unsigned NumElts) { + LLT LeftoverTy; + assert(Ty.isVector() && "Expected vector type"); + LLT EltTy = Ty.getElementType(); + LLT NarrowTy = (NumElts == 1) ? EltTy : LLT::fixed_vector(NumElts, EltTy); + int NumParts, NumLeftover; + std::tie(NumParts, NumLeftover) = + getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy); + + assert(NumParts > 0 && "Error in getNarrowTypeBreakDown"); + for (int i = 0; i < NumParts; ++i) { + DstOps.push_back(NarrowTy); + } + + if (LeftoverTy.isValid()) { + assert(NumLeftover == 1 && "expected exactly one leftover"); + DstOps.push_back(LeftoverTy); + } +} + +/// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps +/// made from \p Op depending on operand type. +static void broadcastSrcOp(SmallVectorImpl &Ops, unsigned N, + MachineOperand &Op) { + for (unsigned i = 0; i < N; ++i) { + if (Op.isReg()) + Ops.push_back(Op.getReg()); + else if (Op.isImm()) + Ops.push_back(Op.getImm()); + else if (Op.isPredicate()) + Ops.push_back(static_cast(Op.getPredicate())); + else + llvm_unreachable("Unsupported type"); + } } // Handle splitting vector operations which need to have the same number of @@ -3588,335 +3722,116 @@ LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorImplicitDef( // s64 = G_SHL s64, s32 LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorMultiEltType( - MachineInstr &MI, unsigned TypeIdx, LLT NarrowTyArg) { - if (TypeIdx != 0) - return UnableToLegalize; - - const LLT NarrowTy0 = NarrowTyArg; - const Register DstReg = MI.getOperand(0).getReg(); - LLT DstTy = MRI.getType(DstReg); - LLT LeftoverTy0; - - // All of the operands need to have the same number of elements, so if we can - // determine a type breakdown for the result type, we can for all of the - // source types. - int NumParts = getNarrowTypeBreakDown(DstTy, NarrowTy0, LeftoverTy0).first; - if (NumParts < 0) - return UnableToLegalize; - - SmallVector NewInsts; - - SmallVector DstRegs, LeftoverDstRegs; - SmallVector PartRegs, LeftoverRegs; - - for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I) { - Register SrcReg = MI.getOperand(I).getReg(); - LLT SrcTyI = MRI.getType(SrcReg); - const auto NewEC = NarrowTy0.isVector() ? NarrowTy0.getElementCount() - : ElementCount::getFixed(1); - LLT NarrowTyI = LLT::scalarOrVector(NewEC, SrcTyI.getScalarType()); - LLT LeftoverTyI; - - // Split this operand into the requested typed registers, and any leftover - // required to reproduce the original type. - if (!extractParts(SrcReg, SrcTyI, NarrowTyI, LeftoverTyI, PartRegs, - LeftoverRegs)) - return UnableToLegalize; - - if (I == 1) { - // For the first operand, create an instruction for each part and setup - // the result. - for (Register PartReg : PartRegs) { - Register PartDstReg = MRI.createGenericVirtualRegister(NarrowTy0); - NewInsts.push_back(MIRBuilder.buildInstrNoInsert(MI.getOpcode()) - .addDef(PartDstReg) - .addUse(PartReg)); - DstRegs.push_back(PartDstReg); - } - - for (Register LeftoverReg : LeftoverRegs) { - Register PartDstReg = MRI.createGenericVirtualRegister(LeftoverTy0); - NewInsts.push_back(MIRBuilder.buildInstrNoInsert(MI.getOpcode()) - .addDef(PartDstReg) - .addUse(LeftoverReg)); - LeftoverDstRegs.push_back(PartDstReg); - } + GenericMachineInstr &MI, unsigned NumElts, + std::initializer_list NonVecOpIndices) { + assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) && + "Non-compatible opcode or not specified non-vector operands"); + unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements(); + + unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs(); + unsigned NumDefs = MI.getNumDefs(); + + // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output. + // Build instructions with DstOps to use instruction found by CSE directly. + // CSE copies found instruction into given vreg when building with vreg dest. + SmallVector, 2> OutputOpsPieces(NumDefs); + // Output registers will be taken from created instructions. + SmallVector, 2> OutputRegs(NumDefs); + for (unsigned i = 0; i < NumDefs; ++i) { + makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts); + } + + // Split vector input operands into sub-vectors with NumElts elts + Leftover. + // Operands listed in NonVecOpIndices will be used as is without splitting; + // examples: compare predicate in icmp and fcmp (op 1), vector select with i1 + // scalar condition (op 1), immediate in sext_inreg (op 2). + SmallVector, 3> InputOpsPieces(NumInputs); + for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands(); + ++UseIdx, ++UseNo) { + if (is_contained(NonVecOpIndices, UseIdx)) { + broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(), + MI.getOperand(UseIdx)); } else { - assert(NewInsts.size() == PartRegs.size() + LeftoverRegs.size()); - - // Add the newly created operand splits to the existing instructions. The - // odd-sized pieces are ordered after the requested NarrowTyArg sized - // pieces. - unsigned InstCount = 0; - for (unsigned J = 0, JE = PartRegs.size(); J != JE; ++J) - NewInsts[InstCount++].addUse(PartRegs[J]); - for (unsigned J = 0, JE = LeftoverRegs.size(); J != JE; ++J) - NewInsts[InstCount++].addUse(LeftoverRegs[J]); + SmallVector SplitPieces; + extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces); + for (auto Reg : SplitPieces) + InputOpsPieces[UseNo].push_back(Reg); } - - PartRegs.clear(); - LeftoverRegs.clear(); } - // Insert the newly built operations and rebuild the result register. - for (auto &MIB : NewInsts) - MIRBuilder.insertInstr(MIB); + unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0; - insertParts(DstReg, DstTy, NarrowTy0, DstRegs, LeftoverTy0, LeftoverDstRegs); + // Take i-th piece of each input operand split and build sub-vector/scalar + // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s). + for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) { + SmallVector Defs; + for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo) + Defs.push_back(OutputOpsPieces[DstNo][i]); - MI.eraseFromParent(); - return Legalized; -} + SmallVector Uses; + for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo) + Uses.push_back(InputOpsPieces[InputNo][i]); -LegalizerHelper::LegalizeResult -LegalizerHelper::fewerElementsVectorCasts(MachineInstr &MI, unsigned TypeIdx, - LLT NarrowTy) { - if (TypeIdx != 0) - return UnableToLegalize; - - Register DstReg = MI.getOperand(0).getReg(); - Register SrcReg = MI.getOperand(1).getReg(); - LLT DstTy = MRI.getType(DstReg); - LLT SrcTy = MRI.getType(SrcReg); - - LLT NarrowTy0 = NarrowTy; - LLT NarrowTy1; - unsigned NumParts; - - if (NarrowTy.isVector()) { - // Uneven breakdown not handled. - NumParts = DstTy.getNumElements() / NarrowTy.getNumElements(); - if (NumParts * NarrowTy.getNumElements() != DstTy.getNumElements()) - return UnableToLegalize; - - NarrowTy1 = LLT::vector(NarrowTy.getElementCount(), SrcTy.getElementType()); - } else { - NumParts = DstTy.getNumElements(); - NarrowTy1 = SrcTy.getElementType(); + auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags()); + for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo) + OutputRegs[DstNo].push_back(I.getReg(DstNo)); } - SmallVector SrcRegs, DstRegs; - extractParts(SrcReg, NarrowTy1, NumParts, SrcRegs); - - for (unsigned I = 0; I < NumParts; ++I) { - Register DstReg = MRI.createGenericVirtualRegister(NarrowTy0); - MachineInstr *NewInst = - MIRBuilder.buildInstr(MI.getOpcode(), {DstReg}, {SrcRegs[I]}); - - NewInst->setFlags(MI.getFlags()); - DstRegs.push_back(DstReg); + // Merge small outputs into MI's output for each def operand. + if (NumLeftovers) { + for (unsigned i = 0; i < NumDefs; ++i) + mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]); + } else { + for (unsigned i = 0; i < NumDefs; ++i) + MIRBuilder.buildMerge(MI.getReg(i), OutputRegs[i]); } - if (NarrowTy.isVector()) - MIRBuilder.buildConcatVectors(DstReg, DstRegs); - else - MIRBuilder.buildBuildVector(DstReg, DstRegs); - MI.eraseFromParent(); return Legalized; } LegalizerHelper::LegalizeResult -LegalizerHelper::fewerElementsVectorCmp(MachineInstr &MI, unsigned TypeIdx, - LLT NarrowTy) { - Register DstReg = MI.getOperand(0).getReg(); - Register Src0Reg = MI.getOperand(2).getReg(); - LLT DstTy = MRI.getType(DstReg); - LLT SrcTy = MRI.getType(Src0Reg); - - unsigned NumParts; - LLT NarrowTy0, NarrowTy1; - - if (TypeIdx == 0) { - unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1; - unsigned OldElts = DstTy.getNumElements(); - - NarrowTy0 = NarrowTy; - NumParts = NarrowTy.isVector() ? (OldElts / NewElts) : DstTy.getNumElements(); - NarrowTy1 = NarrowTy.isVector() ? LLT::vector(NarrowTy.getElementCount(), - SrcTy.getScalarSizeInBits()) - : SrcTy.getElementType(); - - } else { - unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1; - unsigned OldElts = SrcTy.getNumElements(); - - NumParts = NarrowTy.isVector() ? (OldElts / NewElts) : - NarrowTy.getNumElements(); - NarrowTy0 = - LLT::vector(NarrowTy.getElementCount(), DstTy.getScalarSizeInBits()); - NarrowTy1 = NarrowTy; +LegalizerHelper::fewerElementsVectorPhi(GenericMachineInstr &MI, + unsigned NumElts) { + unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements(); + + unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs(); + unsigned NumDefs = MI.getNumDefs(); + + SmallVector OutputOpsPieces; + SmallVector OutputRegs; + makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts); + + // Instructions that perform register split will be inserted in basic block + // where register is defined (basic block is in the next operand). + SmallVector, 3> InputOpsPieces(NumInputs / 2); + for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands(); + UseIdx += 2, ++UseNo) { + MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB(); + MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator()); + extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo]); } - // FIXME: Don't know how to handle the situation where the small vectors - // aren't all the same size yet. - if (NarrowTy1.isVector() && - NarrowTy1.getNumElements() * NumParts != DstTy.getNumElements()) - return UnableToLegalize; - - CmpInst::Predicate Pred - = static_cast(MI.getOperand(1).getPredicate()); - - SmallVector Src1Regs, Src2Regs, DstRegs; - extractParts(MI.getOperand(2).getReg(), NarrowTy1, NumParts, Src1Regs); - extractParts(MI.getOperand(3).getReg(), NarrowTy1, NumParts, Src2Regs); + // Build PHIs with fewer elements. + unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0; + MIRBuilder.setInsertPt(*MI.getParent(), MI); + for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) { + auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI); + Phi.addDef( + MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI))); + OutputRegs.push_back(Phi.getReg(0)); - for (unsigned I = 0; I < NumParts; ++I) { - Register DstReg = MRI.createGenericVirtualRegister(NarrowTy0); - DstRegs.push_back(DstReg); - - if (MI.getOpcode() == TargetOpcode::G_ICMP) - MIRBuilder.buildICmp(Pred, DstReg, Src1Regs[I], Src2Regs[I]); - else { - MachineInstr *NewCmp - = MIRBuilder.buildFCmp(Pred, DstReg, Src1Regs[I], Src2Regs[I]); - NewCmp->setFlags(MI.getFlags()); + for (unsigned j = 0; j < NumInputs / 2; ++j) { + Phi.addUse(InputOpsPieces[j][i]); + Phi.add(MI.getOperand(1 + j * 2 + 1)); } } - if (NarrowTy1.isVector()) - MIRBuilder.buildConcatVectors(DstReg, DstRegs); - else - MIRBuilder.buildBuildVector(DstReg, DstRegs); - - MI.eraseFromParent(); - return Legalized; -} - -LegalizerHelper::LegalizeResult -LegalizerHelper::fewerElementsVectorSelect(MachineInstr &MI, unsigned TypeIdx, - LLT NarrowTy) { - Register DstReg = MI.getOperand(0).getReg(); - Register CondReg = MI.getOperand(1).getReg(); - - unsigned NumParts = 0; - LLT NarrowTy0, NarrowTy1; - - LLT DstTy = MRI.getType(DstReg); - LLT CondTy = MRI.getType(CondReg); - unsigned Size = DstTy.getSizeInBits(); - - assert(TypeIdx == 0 || CondTy.isVector()); - - if (TypeIdx == 0) { - NarrowTy0 = NarrowTy; - NarrowTy1 = CondTy; - - unsigned NarrowSize = NarrowTy0.getSizeInBits(); - // FIXME: Don't know how to handle the situation where the small vectors - // aren't all the same size yet. - if (Size % NarrowSize != 0) - return UnableToLegalize; - - NumParts = Size / NarrowSize; - - // Need to break down the condition type - if (CondTy.isVector()) { - if (CondTy.getNumElements() == NumParts) - NarrowTy1 = CondTy.getElementType(); - else - NarrowTy1 = - LLT::vector(CondTy.getElementCount().divideCoefficientBy(NumParts), - CondTy.getScalarSizeInBits()); - } + // Merge small outputs into MI's def. + if (NumLeftovers) { + mergeMixedSubvectors(MI.getReg(0), OutputRegs); } else { - NumParts = CondTy.getNumElements(); - if (NarrowTy.isVector()) { - // TODO: Handle uneven breakdown. - if (NumParts * NarrowTy.getNumElements() != CondTy.getNumElements()) - return UnableToLegalize; - - return UnableToLegalize; - } else { - NarrowTy0 = DstTy.getElementType(); - NarrowTy1 = NarrowTy; - } - } - - SmallVector DstRegs, Src0Regs, Src1Regs, Src2Regs; - if (CondTy.isVector()) - extractParts(MI.getOperand(1).getReg(), NarrowTy1, NumParts, Src0Regs); - - extractParts(MI.getOperand(2).getReg(), NarrowTy0, NumParts, Src1Regs); - extractParts(MI.getOperand(3).getReg(), NarrowTy0, NumParts, Src2Regs); - - for (unsigned i = 0; i < NumParts; ++i) { - Register DstReg = MRI.createGenericVirtualRegister(NarrowTy0); - MIRBuilder.buildSelect(DstReg, CondTy.isVector() ? Src0Regs[i] : CondReg, - Src1Regs[i], Src2Regs[i]); - DstRegs.push_back(DstReg); - } - - if (NarrowTy0.isVector()) - MIRBuilder.buildConcatVectors(DstReg, DstRegs); - else - MIRBuilder.buildBuildVector(DstReg, DstRegs); - - MI.eraseFromParent(); - return Legalized; -} - -LegalizerHelper::LegalizeResult -LegalizerHelper::fewerElementsVectorPhi(MachineInstr &MI, unsigned TypeIdx, - LLT NarrowTy) { - const Register DstReg = MI.getOperand(0).getReg(); - LLT PhiTy = MRI.getType(DstReg); - LLT LeftoverTy; - - // All of the operands need to have the same number of elements, so if we can - // determine a type breakdown for the result type, we can for all of the - // source types. - int NumParts, NumLeftover; - std::tie(NumParts, NumLeftover) - = getNarrowTypeBreakDown(PhiTy, NarrowTy, LeftoverTy); - if (NumParts < 0) - return UnableToLegalize; - - SmallVector DstRegs, LeftoverDstRegs; - SmallVector NewInsts; - - const int TotalNumParts = NumParts + NumLeftover; - - // Insert the new phis in the result block first. - for (int I = 0; I != TotalNumParts; ++I) { - LLT Ty = I < NumParts ? NarrowTy : LeftoverTy; - Register PartDstReg = MRI.createGenericVirtualRegister(Ty); - NewInsts.push_back(MIRBuilder.buildInstr(TargetOpcode::G_PHI) - .addDef(PartDstReg)); - if (I < NumParts) - DstRegs.push_back(PartDstReg); - else - LeftoverDstRegs.push_back(PartDstReg); - } - - MachineBasicBlock *MBB = MI.getParent(); - MIRBuilder.setInsertPt(*MBB, MBB->getFirstNonPHI()); - insertParts(DstReg, PhiTy, NarrowTy, DstRegs, LeftoverTy, LeftoverDstRegs); - - SmallVector PartRegs, LeftoverRegs; - - // Insert code to extract the incoming values in each predecessor block. - for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) { - PartRegs.clear(); - LeftoverRegs.clear(); - - Register SrcReg = MI.getOperand(I).getReg(); - MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB(); - MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator()); - - LLT Unused; - if (!extractParts(SrcReg, PhiTy, NarrowTy, Unused, PartRegs, - LeftoverRegs)) - return UnableToLegalize; - - // Add the newly created operand splits to the existing instructions. The - // odd-sized pieces are ordered after the requested NarrowTyArg sized - // pieces. - for (int J = 0; J != TotalNumParts; ++J) { - MachineInstrBuilder MIB = NewInsts[J]; - MIB.addUse(J < NumParts ? PartRegs[J] : LeftoverRegs[J - NumParts]); - MIB.addMBB(&OpMBB); - } + MIRBuilder.buildMerge(MI.getReg(0), OutputRegs); } MI.eraseFromParent(); @@ -3927,27 +3842,36 @@ LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorUnmergeValues(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy) { - if (TypeIdx != 1) - return UnableToLegalize; - const int NumDst = MI.getNumOperands() - 1; const Register SrcReg = MI.getOperand(NumDst).getReg(); - LLT SrcTy = MRI.getType(SrcReg); - LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); + LLT SrcTy = MRI.getType(SrcReg); - // TODO: Create sequence of extracts. - if (DstTy == NarrowTy) + if (TypeIdx != 1 || NarrowTy == DstTy) return UnableToLegalize; - LLT GCDTy = getGCDType(SrcTy, NarrowTy); - if (DstTy == GCDTy) { - // This would just be a copy of the same unmerge. - // TODO: Create extracts, pad with undef and create intermediate merges. + // Requires compatible types. Otherwise SrcReg should have been defined by + // merge-like instruction that would get artifact combined. Most likely + // instruction that defines SrcReg has to perform more/fewer elements + // legalization compatible with NarrowTy. + assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types"); + assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type"); + + if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) || + (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0)) return UnableToLegalize; - } - auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg); + // This is most likely DstTy (smaller then register size) packed in SrcTy + // (larger then register size) and since unmerge was not combined it will be + // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy + // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy. + + // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy) + // + // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence + // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg + // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy) + auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg); const int NumUnmerge = Unmerge->getNumOperands() - 1; const int PartsPerUnmerge = NumDst / NumUnmerge; @@ -3963,90 +3887,88 @@ LegalizerHelper::fewerElementsVectorUnmergeValues(MachineInstr &MI, return Legalized; } -LegalizerHelper::LegalizeResult -LegalizerHelper::fewerElementsVectorMulo(MachineInstr &MI, unsigned TypeIdx, - LLT NarrowTy) { - Register Result = MI.getOperand(0).getReg(); - Register Overflow = MI.getOperand(1).getReg(); - Register LHS = MI.getOperand(2).getReg(); - Register RHS = MI.getOperand(3).getReg(); - - LLT SrcTy = MRI.getType(LHS); - if (!SrcTy.isVector()) - return UnableToLegalize; - - LLT ElementType = SrcTy.getElementType(); - LLT OverflowElementTy = MRI.getType(Overflow).getElementType(); - const ElementCount NumResult = SrcTy.getElementCount(); - LLT GCDTy = getGCDType(SrcTy, NarrowTy); - - // Unmerge the operands to smaller parts of GCD type. - auto UnmergeLHS = MIRBuilder.buildUnmerge(GCDTy, LHS); - auto UnmergeRHS = MIRBuilder.buildUnmerge(GCDTy, RHS); - - const int NumOps = UnmergeLHS->getNumOperands() - 1; - const ElementCount PartsPerUnmerge = NumResult.divideCoefficientBy(NumOps); - LLT OverflowTy = LLT::scalarOrVector(PartsPerUnmerge, OverflowElementTy); - LLT ResultTy = LLT::scalarOrVector(PartsPerUnmerge, ElementType); - - // Perform the operation over unmerged parts. - SmallVector ResultParts; - SmallVector OverflowParts; - for (int I = 0; I != NumOps; ++I) { - Register Operand1 = UnmergeLHS->getOperand(I).getReg(); - Register Operand2 = UnmergeRHS->getOperand(I).getReg(); - auto PartMul = MIRBuilder.buildInstr(MI.getOpcode(), {ResultTy, OverflowTy}, - {Operand1, Operand2}); - ResultParts.push_back(PartMul->getOperand(0).getReg()); - OverflowParts.push_back(PartMul->getOperand(1).getReg()); - } - - LLT ResultLCMTy = buildLCMMergePieces(SrcTy, NarrowTy, GCDTy, ResultParts); - LLT OverflowLCMTy = - LLT::scalarOrVector(ResultLCMTy.getElementCount(), OverflowElementTy); - - // Recombine the pieces to the original result and overflow registers. - buildWidenedRemergeToDst(Result, ResultLCMTy, ResultParts); - buildWidenedRemergeToDst(Overflow, OverflowLCMTy, OverflowParts); - MI.eraseFromParent(); - return Legalized; -} - -// Handle FewerElementsVector a G_BUILD_VECTOR or G_CONCAT_VECTORS that produces -// a vector -// -// Create a G_BUILD_VECTOR or G_CONCAT_VECTORS of NarrowTy pieces, padding with -// undef as necessary. -// -// %3:_(<3 x s16>) = G_BUILD_VECTOR %0, %1, %2 -// -> <2 x s16> -// -// %4:_(s16) = G_IMPLICIT_DEF -// %5:_(<2 x s16>) = G_BUILD_VECTOR %0, %1 -// %6:_(<2 x s16>) = G_BUILD_VECTOR %2, %4 -// %7:_(<2 x s16>) = G_IMPLICIT_DEF -// %8:_(<6 x s16>) = G_CONCAT_VECTORS %5, %6, %7 -// %3:_(<3 x s16>), %8:_(<3 x s16>) = G_UNMERGE_VALUES %8 LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy) { Register DstReg = MI.getOperand(0).getReg(); LLT DstTy = MRI.getType(DstReg); LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); - LLT GCDTy = getGCDType(getGCDType(SrcTy, NarrowTy), DstTy); + // Requires compatible types. Otherwise user of DstReg did not perform unmerge + // that should have been artifact combined. Most likely instruction that uses + // DstReg has to do more/fewer elements legalization compatible with NarrowTy. + assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types"); + assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type"); + if (NarrowTy == SrcTy) + return UnableToLegalize; - // Break into a common type - SmallVector Parts; - for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) - extractGCDType(Parts, GCDTy, MO.getReg()); + // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use + // is for old mir tests. Since the changes to more/fewer elements it should no + // longer be possible to generate MIR like this when starting from llvm-ir + // because LCMTy approach was replaced with merge/unmerge to vector elements. + if (TypeIdx == 1) { + assert(SrcTy.isVector() && "Expected vector types"); + assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type"); + if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) || + (NarrowTy.getNumElements() >= SrcTy.getNumElements())) + return UnableToLegalize; + // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy) + // + // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy) + // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy) + // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4 + // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6 + // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8 + // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11 + + SmallVector Elts; + LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType(); + for (unsigned i = 1; i < MI.getNumOperands(); ++i) { + auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg()); + for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j) + Elts.push_back(Unmerge.getReg(j)); + } - // Build the requested new merge, padding with undef. - LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, - TargetOpcode::G_ANYEXT); + SmallVector NarrowTyElts; + unsigned NumNarrowTyElts = NarrowTy.getNumElements(); + unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts; + for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces; + ++i, Offset += NumNarrowTyElts) { + ArrayRef Pieces(&Elts[Offset], NumNarrowTyElts); + NarrowTyElts.push_back(MIRBuilder.buildMerge(NarrowTy, Pieces).getReg(0)); + } - // Pack into the original result register. - buildWidenedRemergeToDst(DstReg, LCMTy, Parts); + MIRBuilder.buildMerge(DstReg, NarrowTyElts); + MI.eraseFromParent(); + return Legalized; + } + + assert(TypeIdx == 0 && "Bad type index"); + if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) || + (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0)) + return UnableToLegalize; + // This is most likely SrcTy (smaller then register size) packed in DstTy + // (larger then register size) and since merge was not combined it will be + // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy + // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy. + + // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4 + // + // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg + // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4 + // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence + SmallVector NarrowTyElts; + unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements(); + unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1; + unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts; + for (unsigned i = 0; i < NumParts; ++i) { + SmallVector Sources; + for (unsigned j = 0; j < NumElts; ++j) + Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg()); + NarrowTyElts.push_back(MIRBuilder.buildMerge(NarrowTy, Sources).getReg(0)); + } + + MIRBuilder.buildMerge(DstReg, NarrowTyElts); MI.eraseFromParent(); return Legalized; } @@ -4217,164 +4139,15 @@ LegalizerHelper::reduceLoadStoreWidth(GLoadStore &LdStMI, unsigned TypeIdx, return Legalized; } -LegalizerHelper::LegalizeResult -LegalizerHelper::reduceOperationWidth(MachineInstr &MI, unsigned int TypeIdx, - LLT NarrowTy) { - assert(TypeIdx == 0 && "only one type index expected"); - - const unsigned Opc = MI.getOpcode(); - const int NumDefOps = MI.getNumExplicitDefs(); - const int NumSrcOps = MI.getNumOperands() - NumDefOps; - const unsigned Flags = MI.getFlags(); - const unsigned NarrowSize = NarrowTy.getSizeInBits(); - const LLT NarrowScalarTy = LLT::scalar(NarrowSize); - - assert(MI.getNumOperands() <= 4 && "expected instruction with either 1 " - "result and 1-3 sources or 2 results and " - "1-2 sources"); - - SmallVector DstRegs; - for (int I = 0; I < NumDefOps; ++I) - DstRegs.push_back(MI.getOperand(I).getReg()); - - // First of all check whether we are narrowing (changing the element type) - // or reducing the vector elements - const LLT DstTy = MRI.getType(DstRegs[0]); - const bool IsNarrow = NarrowTy.getScalarType() != DstTy.getScalarType(); - - SmallVector ExtractedRegs[3]; - SmallVector Parts; - - // Break down all the sources into NarrowTy pieces we can operate on. This may - // involve creating merges to a wider type, padded with undef. - for (int I = 0; I != NumSrcOps; ++I) { - Register SrcReg = MI.getOperand(I + NumDefOps).getReg(); - LLT SrcTy = MRI.getType(SrcReg); - - // The type to narrow SrcReg to. For narrowing, this is a smaller scalar. - // For fewerElements, this is a smaller vector with the same element type. - LLT OpNarrowTy; - if (IsNarrow) { - OpNarrowTy = NarrowScalarTy; - - // In case of narrowing, we need to cast vectors to scalars for this to - // work properly - // FIXME: Can we do without the bitcast here if we're narrowing? - if (SrcTy.isVector()) { - SrcTy = LLT::scalar(SrcTy.getSizeInBits()); - SrcReg = MIRBuilder.buildBitcast(SrcTy, SrcReg).getReg(0); - } - } else { - auto NarrowEC = NarrowTy.isVector() ? NarrowTy.getElementCount() - : ElementCount::getFixed(1); - OpNarrowTy = LLT::scalarOrVector(NarrowEC, SrcTy.getScalarType()); - } - - LLT GCDTy = extractGCDType(ExtractedRegs[I], SrcTy, OpNarrowTy, SrcReg); - - // Build a sequence of NarrowTy pieces in ExtractedRegs for this operand. - buildLCMMergePieces(SrcTy, OpNarrowTy, GCDTy, ExtractedRegs[I], - TargetOpcode::G_ANYEXT); - } - - SmallVector ResultRegs[2]; - - // Input operands for each sub-instruction. - SmallVector InputRegs(NumSrcOps, Register()); - - int NumParts = ExtractedRegs[0].size(); - const unsigned DstSize = DstTy.getSizeInBits(); - const LLT DstScalarTy = LLT::scalar(DstSize); - - // Narrowing needs to use scalar types - LLT DstLCMTy, NarrowDstTy; - if (IsNarrow) { - DstLCMTy = getLCMType(DstScalarTy, NarrowScalarTy); - NarrowDstTy = NarrowScalarTy; - } else { - DstLCMTy = getLCMType(DstTy, NarrowTy); - NarrowDstTy = NarrowTy; - } - - // We widened the source registers to satisfy merge/unmerge size - // constraints. We'll have some extra fully undef parts. - const int NumRealParts = (DstSize + NarrowSize - 1) / NarrowSize; - - for (int I = 0; I != NumRealParts; ++I) { - // Emit this instruction on each of the split pieces. - for (int J = 0; J != NumSrcOps; ++J) - InputRegs[J] = ExtractedRegs[J][I]; - - MachineInstrBuilder Inst; - if (NumDefOps == 1) - Inst = MIRBuilder.buildInstr(Opc, {NarrowDstTy}, InputRegs, Flags); - else - Inst = MIRBuilder.buildInstr(Opc, {NarrowDstTy, NarrowDstTy}, InputRegs, - Flags); - - for (int J = 0; J != NumDefOps; ++J) - ResultRegs[J].push_back(Inst.getReg(J)); - } - - // Fill out the widened result with undef instead of creating instructions - // with undef inputs. - int NumUndefParts = NumParts - NumRealParts; - if (NumUndefParts != 0) { - Register Undef = MIRBuilder.buildUndef(NarrowDstTy).getReg(0); - for (int I = 0; I != NumDefOps; ++I) - ResultRegs[I].append(NumUndefParts, Undef); - } - - // Extract the possibly padded result. Use a scratch register if we need to do - // a final bitcast, otherwise use the original result register. - Register MergeDstReg; - for (int I = 0; I != NumDefOps; ++I) { - if (IsNarrow && DstTy.isVector()) - MergeDstReg = MRI.createGenericVirtualRegister(DstScalarTy); - else - MergeDstReg = DstRegs[I]; - - buildWidenedRemergeToDst(MergeDstReg, DstLCMTy, ResultRegs[I]); - - // Recast to vector if we narrowed a vector - if (IsNarrow && DstTy.isVector()) - MIRBuilder.buildBitcast(DstRegs[I], MergeDstReg); - } - - MI.eraseFromParent(); - return Legalized; -} - -LegalizerHelper::LegalizeResult -LegalizerHelper::fewerElementsVectorSextInReg(MachineInstr &MI, unsigned TypeIdx, - LLT NarrowTy) { - Register DstReg = MI.getOperand(0).getReg(); - Register SrcReg = MI.getOperand(1).getReg(); - int64_t Imm = MI.getOperand(2).getImm(); - - LLT DstTy = MRI.getType(DstReg); - - SmallVector Parts; - LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg); - LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts); - - for (Register &R : Parts) - R = MIRBuilder.buildSExtInReg(NarrowTy, R, Imm).getReg(0); - - buildWidenedRemergeToDst(DstReg, LCMTy, Parts); - - MI.eraseFromParent(); - return Legalized; -} - LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy) { using namespace TargetOpcode; + GenericMachineInstr &GMI = cast(MI); + unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1; switch (MI.getOpcode()) { case G_IMPLICIT_DEF: - return fewerElementsVectorImplicitDef(MI, TypeIdx, NarrowTy); case G_TRUNC: case G_AND: case G_OR: @@ -4439,10 +4212,8 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, case G_SSUBSAT: case G_UADDSAT: case G_USUBSAT: - return reduceOperationWidth(MI, TypeIdx, NarrowTy); case G_UMULO: case G_SMULO: - return fewerElementsVectorMulo(MI, TypeIdx, NarrowTy); case G_SHL: case G_LSHR: case G_ASHR: @@ -4454,7 +4225,6 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, case G_CTTZ_ZERO_UNDEF: case G_CTPOP: case G_FCOPYSIGN: - return fewerElementsVectorMultiEltType(MI, TypeIdx, NarrowTy); case G_ZEXT: case G_SEXT: case G_ANYEXT: @@ -4467,14 +4237,16 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, case G_INTTOPTR: case G_PTRTOINT: case G_ADDRSPACE_CAST: - return fewerElementsVectorCasts(MI, TypeIdx, NarrowTy); + return fewerElementsVectorMultiEltType(GMI, NumElts); case G_ICMP: case G_FCMP: - return fewerElementsVectorCmp(MI, TypeIdx, NarrowTy); + return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/}); case G_SELECT: - return fewerElementsVectorSelect(MI, TypeIdx, NarrowTy); + if (MRI.getType(MI.getOperand(1).getReg()).isVector()) + return fewerElementsVectorMultiEltType(GMI, NumElts); + return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/}); case G_PHI: - return fewerElementsVectorPhi(MI, TypeIdx, NarrowTy); + return fewerElementsVectorPhi(GMI, NumElts); case G_UNMERGE_VALUES: return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy); case G_BUILD_VECTOR: @@ -4491,7 +4263,7 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, case G_STORE: return reduceLoadStoreWidth(cast(MI), TypeIdx, NarrowTy); case G_SEXT_INREG: - return fewerElementsVectorSextInReg(MI, TypeIdx, NarrowTy); + return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/}); GISEL_VECREDUCE_CASES_NONSEQ return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy); case G_SHUFFLE_VECTOR: @@ -5053,6 +4825,15 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx, case TargetOpcode::G_AND: case TargetOpcode::G_OR: case TargetOpcode::G_XOR: + case TargetOpcode::G_ADD: + case TargetOpcode::G_SUB: + case TargetOpcode::G_MUL: + case TargetOpcode::G_FADD: + case TargetOpcode::G_FMUL: + case TargetOpcode::G_UADDSAT: + case TargetOpcode::G_USUBSAT: + case TargetOpcode::G_SADDSAT: + case TargetOpcode::G_SSUBSAT: case TargetOpcode::G_SMIN: case TargetOpcode::G_SMAX: case TargetOpcode::G_UMIN: @@ -5070,6 +4851,17 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx, Observer.changedInstr(MI); return Legalized; } + case TargetOpcode::G_FMA: + case TargetOpcode::G_FSHR: + case TargetOpcode::G_FSHL: { + Observer.changingInstr(MI); + moreElementsVectorSrc(MI, MoreTy, 1); + moreElementsVectorSrc(MI, MoreTy, 2); + moreElementsVectorSrc(MI, MoreTy, 3); + moreElementsVectorDst(MI, MoreTy, 0); + Observer.changedInstr(MI); + return Legalized; + } case TargetOpcode::G_EXTRACT: if (TypeIdx != 1) return UnableToLegalize; @@ -5079,6 +4871,11 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx, return Legalized; case TargetOpcode::G_INSERT: case TargetOpcode::G_FREEZE: + case TargetOpcode::G_FNEG: + case TargetOpcode::G_FABS: + case TargetOpcode::G_BSWAP: + case TargetOpcode::G_FCANONICALIZE: + case TargetOpcode::G_SEXT_INREG: if (TypeIdx != 0) return UnableToLegalize; Observer.changingInstr(MI); @@ -5098,30 +4895,34 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx, moreElementsVectorDst(MI, MoreTy, 0); Observer.changedInstr(MI); return Legalized; - case TargetOpcode::G_UNMERGE_VALUES: { - if (TypeIdx != 1) - return UnableToLegalize; - - LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); - int NumDst = MI.getNumOperands() - 1; - moreElementsVectorSrc(MI, MoreTy, NumDst); - - auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES); - for (int I = 0; I != NumDst; ++I) - MIB.addDef(MI.getOperand(I).getReg()); + case TargetOpcode::G_UNMERGE_VALUES: + return UnableToLegalize; + case TargetOpcode::G_PHI: + return moreElementsVectorPhi(MI, TypeIdx, MoreTy); + case TargetOpcode::G_SHUFFLE_VECTOR: + return moreElementsVectorShuffle(MI, TypeIdx, MoreTy); + case TargetOpcode::G_BUILD_VECTOR: { + SmallVector Elts; + for (auto Op : MI.uses()) { + Elts.push_back(Op.getReg()); + } - int NewNumDst = MoreTy.getSizeInBits() / DstTy.getSizeInBits(); - for (int I = NumDst; I != NewNumDst; ++I) - MIB.addDef(MRI.createGenericVirtualRegister(DstTy)); + for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) { + Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType())); + } - MIB.addUse(MI.getOperand(NumDst).getReg()); + MIRBuilder.buildDeleteTrailingVectorElements( + MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts)); MI.eraseFromParent(); return Legalized; } - case TargetOpcode::G_PHI: - return moreElementsVectorPhi(MI, TypeIdx, MoreTy); - case TargetOpcode::G_SHUFFLE_VECTOR: - return moreElementsVectorShuffle(MI, TypeIdx, MoreTy); + case TargetOpcode::G_TRUNC: { + Observer.changingInstr(MI); + moreElementsVectorSrc(MI, MoreTy, 1); + moreElementsVectorDst(MI, MoreTy, 0); + Observer.changedInstr(MI); + return Legalized; + } default: return UnableToLegalize; } @@ -6778,6 +6579,24 @@ LegalizerHelper::lowerExtractInsertVectorElt(MachineInstr &MI) { LLT VecTy = MRI.getType(SrcVec); LLT EltTy = VecTy.getElementType(); + unsigned NumElts = VecTy.getNumElements(); + + int64_t IdxVal; + if (mi_match(Idx, MRI, m_ICst(IdxVal)) && IdxVal <= NumElts) { + SmallVector SrcRegs; + extractParts(SrcVec, EltTy, NumElts, SrcRegs); + + if (InsertVal) { + SrcRegs[IdxVal] = MI.getOperand(2).getReg(); + MIRBuilder.buildMerge(DstReg, SrcRegs); + } else { + MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]); + } + + MI.eraseFromParent(); + return Legalized; + } + if (!EltTy.isByteSized()) { // Not implemented. LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n"); return UnableToLegalize; @@ -6796,7 +6615,6 @@ LegalizerHelper::lowerExtractInsertVectorElt(MachineInstr &MI) { // if the index is out of bounds. Register EltPtr = getVectorElementPointer(StackTemp.getReg(0), VecTy, Idx); - int64_t IdxVal; if (mi_match(Idx, MRI, m_ICst(IdxVal))) { int64_t Offset = IdxVal * EltBytes; PtrInfo = PtrInfo.getWithOffset(Offset); @@ -6923,6 +6741,32 @@ LegalizerHelper::lowerExtract(MachineInstr &MI) { LLT DstTy = MRI.getType(Dst); LLT SrcTy = MRI.getType(Src); + // Extract sub-vector or one element + if (SrcTy.isVector()) { + unsigned SrcEltSize = SrcTy.getElementType().getSizeInBits(); + unsigned DstSize = DstTy.getSizeInBits(); + + if ((Offset % SrcEltSize == 0) && (DstSize % SrcEltSize == 0) && + (Offset + DstSize <= SrcTy.getSizeInBits())) { + // Unmerge and allow access to each Src element for the artifact combiner. + auto Unmerge = MIRBuilder.buildUnmerge(SrcTy.getElementType(), Src); + + // Take element(s) we need to extract and copy it (merge them). + SmallVector SubVectorElts; + for (unsigned Idx = Offset / SrcEltSize; + Idx < (Offset + DstSize) / SrcEltSize; ++Idx) { + SubVectorElts.push_back(Unmerge.getReg(Idx)); + } + if (SubVectorElts.size() == 1) + MIRBuilder.buildCopy(Dst, SubVectorElts[0]); + else + MIRBuilder.buildMerge(Dst, SubVectorElts); + + MI.eraseFromParent(); + return Legalized; + } + } + if (DstTy.isScalar() && (SrcTy.isScalar() || (SrcTy.isVector() && DstTy == SrcTy.getElementType()))) { @@ -6956,6 +6800,45 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerInsert(MachineInstr &MI) { LLT DstTy = MRI.getType(Src); LLT InsertTy = MRI.getType(InsertSrc); + // Insert sub-vector or one element + if (DstTy.isVector() && !InsertTy.isPointer()) { + LLT EltTy = DstTy.getElementType(); + unsigned EltSize = EltTy.getSizeInBits(); + unsigned InsertSize = InsertTy.getSizeInBits(); + + if ((Offset % EltSize == 0) && (InsertSize % EltSize == 0) && + (Offset + InsertSize <= DstTy.getSizeInBits())) { + auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, Src); + SmallVector DstElts; + unsigned Idx = 0; + // Elements from Src before insert start Offset + for (; Idx < Offset / EltSize; ++Idx) { + DstElts.push_back(UnmergeSrc.getReg(Idx)); + } + + // Replace elements in Src with elements from InsertSrc + if (InsertTy.getSizeInBits() > EltSize) { + auto UnmergeInsertSrc = MIRBuilder.buildUnmerge(EltTy, InsertSrc); + for (unsigned i = 0; Idx < (Offset + InsertSize) / EltSize; + ++Idx, ++i) { + DstElts.push_back(UnmergeInsertSrc.getReg(i)); + } + } else { + DstElts.push_back(InsertSrc); + ++Idx; + } + + // Remaining elements from Src after insert + for (; Idx < DstTy.getNumElements(); ++Idx) { + DstElts.push_back(UnmergeSrc.getReg(Idx)); + } + + MIRBuilder.buildMerge(Dst, DstElts); + MI.eraseFromParent(); + return Legalized; + } + } + if (InsertTy.isVector() || (DstTy.isVector() && DstTy.getElementType() != InsertTy)) return UnableToLegalize; diff --git a/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp b/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp index 03dda806cb1e..de8dbd456901 100644 --- a/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp @@ -554,12 +554,11 @@ bool LoadStoreOpt::mergeBlockStores(MachineBasicBlock &MBB) { bool Changed = false; // Walk through the block bottom-up, looking for merging candidates. StoreMergeCandidate Candidate; - for (auto II = MBB.rbegin(), IE = MBB.rend(); II != IE; ++II) { - MachineInstr &MI = *II; + for (MachineInstr &MI : llvm::reverse(MBB)) { if (InstsToErase.contains(&MI)) continue; - if (auto StoreMI = dyn_cast(&*II)) { + if (auto *StoreMI = dyn_cast(&MI)) { // We have a G_STORE. Add it to the candidate if it writes to an adjacent // address. if (!addStoreToCandidate(*StoreMI, Candidate)) { diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index fb5ed35c1f72..391251886fbb 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -215,6 +215,48 @@ MachineInstrBuilder MachineIRBuilder::buildMaskLowPtrBits(const DstOp &Res, return buildPtrMask(Res, Op0, MaskReg); } +MachineInstrBuilder +MachineIRBuilder::buildPadVectorWithUndefElements(const DstOp &Res, + const SrcOp &Op0) { + LLT ResTy = Res.getLLTTy(*getMRI()); + LLT Op0Ty = Op0.getLLTTy(*getMRI()); + + assert((ResTy.isVector() && Op0Ty.isVector()) && "Non vector type"); + assert((ResTy.getElementType() == Op0Ty.getElementType()) && + "Different vector element types"); + assert((ResTy.getNumElements() > Op0Ty.getNumElements()) && + "Op0 has more elements"); + + auto Unmerge = buildUnmerge(Op0Ty.getElementType(), Op0); + SmallVector Regs; + for (auto Op : Unmerge.getInstr()->defs()) + Regs.push_back(Op.getReg()); + Register Undef = buildUndef(Op0Ty.getElementType()).getReg(0); + unsigned NumberOfPadElts = ResTy.getNumElements() - Regs.size(); + for (unsigned i = 0; i < NumberOfPadElts; ++i) + Regs.push_back(Undef); + return buildMerge(Res, Regs); +} + +MachineInstrBuilder +MachineIRBuilder::buildDeleteTrailingVectorElements(const DstOp &Res, + const SrcOp &Op0) { + LLT ResTy = Res.getLLTTy(*getMRI()); + LLT Op0Ty = Op0.getLLTTy(*getMRI()); + + assert((ResTy.isVector() && Op0Ty.isVector()) && "Non vector type"); + assert((ResTy.getElementType() == Op0Ty.getElementType()) && + "Different vector element types"); + assert((ResTy.getNumElements() < Op0Ty.getNumElements()) && + "Op0 has fewer elements"); + + SmallVector Regs; + auto Unmerge = buildUnmerge(Op0Ty.getElementType(), Op0); + for (unsigned i = 0; i < ResTy.getNumElements(); ++i) + Regs.push_back(Unmerge.getReg(i)); + return buildMerge(Res, Regs); +} + MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) { return buildInstr(TargetOpcode::G_BR).addMBB(&Dest); } @@ -613,10 +655,8 @@ MachineInstrBuilder MachineIRBuilder::buildUnmerge(ArrayRef Res, MachineInstrBuilder MachineIRBuilder::buildUnmerge(LLT Res, const SrcOp &Op) { unsigned NumReg = Op.getLLTTy(*getMRI()).getSizeInBits() / Res.getSizeInBits(); - SmallVector TmpVec; - for (unsigned I = 0; I != NumReg; ++I) - TmpVec.push_back(getMRI()->createGenericVirtualRegister(Res)); - return buildUnmerge(TmpVec, Op); + SmallVector TmpVec(NumReg, Res); + return buildInstr(TargetOpcode::G_UNMERGE_VALUES, TmpVec, Op); } MachineInstrBuilder MachineIRBuilder::buildUnmerge(ArrayRef Res, diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp index b0b84763e922..4981a537dc7c 100644 --- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -923,6 +923,21 @@ LLT llvm::getLCMType(LLT OrigTy, LLT TargetTy) { return LLT::scalar(LCMSize); } +LLT llvm::getCoverTy(LLT OrigTy, LLT TargetTy) { + if (!OrigTy.isVector() || !TargetTy.isVector() || OrigTy == TargetTy || + (OrigTy.getScalarSizeInBits() != TargetTy.getScalarSizeInBits())) + return getLCMType(OrigTy, TargetTy); + + unsigned OrigTyNumElts = OrigTy.getNumElements(); + unsigned TargetTyNumElts = TargetTy.getNumElements(); + if (OrigTyNumElts % TargetTyNumElts == 0) + return OrigTy; + + unsigned NumElts = alignTo(OrigTyNumElts, TargetTyNumElts); + return LLT::scalarOrVector(ElementCount::getFixed(NumElts), + OrigTy.getElementType()); +} + LLT llvm::getGCDType(LLT OrigTy, LLT TargetTy) { const unsigned OrigSize = OrigTy.getSizeInBits(); const unsigned TargetSize = TargetTy.getSizeInBits(); @@ -1184,25 +1199,6 @@ bool llvm::shouldOptForSize(const MachineBasicBlock &MBB, llvm::shouldOptimizeForSize(MBB.getBasicBlock(), PSI, BFI); } -/// These artifacts generally don't have any debug users because they don't -/// directly originate from IR instructions, but instead usually from -/// legalization. Avoiding checking for debug users improves compile time. -/// Note that truncates or extends aren't included because they have IR -/// counterparts which can have debug users after translation. -static bool shouldSkipDbgValueFor(MachineInstr &MI) { - switch (MI.getOpcode()) { - case TargetOpcode::G_UNMERGE_VALUES: - case TargetOpcode::G_MERGE_VALUES: - case TargetOpcode::G_CONCAT_VECTORS: - case TargetOpcode::G_BUILD_VECTOR: - case TargetOpcode::G_EXTRACT: - case TargetOpcode::G_INSERT: - return true; - default: - return false; - } -} - void llvm::saveUsesAndErase(MachineInstr &MI, MachineRegisterInfo &MRI, LostDebugLocObserver *LocObserver, SmallInstListTy &DeadInstChain) { @@ -1212,10 +1208,7 @@ void llvm::saveUsesAndErase(MachineInstr &MI, MachineRegisterInfo &MRI, } LLVM_DEBUG(dbgs() << MI << "Is dead; erasing.\n"); DeadInstChain.remove(&MI); - if (shouldSkipDbgValueFor(MI)) - MI.eraseFromParent(); - else - MI.eraseFromParentAndMarkDBGValuesForRemoval(); + MI.eraseFromParent(); if (LocObserver) LocObserver->checkpoint(false); } diff --git a/llvm/lib/CodeGen/ImplicitNullChecks.cpp b/llvm/lib/CodeGen/ImplicitNullChecks.cpp index 0882ce366c9c..fc97938ccd3e 100644 --- a/llvm/lib/CodeGen/ImplicitNullChecks.cpp +++ b/llvm/lib/CodeGen/ImplicitNullChecks.cpp @@ -242,7 +242,7 @@ bool ImplicitNullChecks::canHandle(const MachineInstr *MI) { auto IsRegMask = [](const MachineOperand &MO) { return MO.isRegMask(); }; (void)IsRegMask; - assert(!llvm::any_of(MI->operands(), IsRegMask) && + assert(llvm::none_of(MI->operands(), IsRegMask) && "Calls were filtered out above!"); auto IsUnordered = [](MachineMemOperand *MMO) { return MMO->isUnordered(); }; diff --git a/llvm/lib/CodeGen/InlineSpiller.cpp b/llvm/lib/CodeGen/InlineSpiller.cpp index fc5ac45752ca..c975013db8c8 100644 --- a/llvm/lib/CodeGen/InlineSpiller.cpp +++ b/llvm/lib/CodeGen/InlineSpiller.cpp @@ -686,9 +686,7 @@ void InlineSpiller::reMaterializeAll() { // Remove any values that were completely rematted. for (Register Reg : RegsToSpill) { LiveInterval &LI = LIS.getInterval(Reg); - for (LiveInterval::vni_iterator I = LI.vni_begin(), E = LI.vni_end(); - I != E; ++I) { - VNInfo *VNI = *I; + for (VNInfo *VNI : llvm::make_range(LI.vni_begin(), LI.vni_end())) { if (VNI->isUnused() || VNI->isPHIDef() || UsedValues.count(VNI)) continue; MachineInstr *MI = LIS.getInstructionFromIndex(VNI->def); diff --git a/llvm/lib/CodeGen/InterferenceCache.cpp b/llvm/lib/CodeGen/InterferenceCache.cpp index a56485cdbc67..3cab9e5734ee 100644 --- a/llvm/lib/CodeGen/InterferenceCache.cpp +++ b/llvm/lib/CodeGen/InterferenceCache.cpp @@ -56,8 +56,8 @@ void InterferenceCache::init(MachineFunction *mf, LIUArray = liuarray; TRI = tri; reinitPhysRegEntries(); - for (unsigned i = 0; i != CacheEntries; ++i) - Entries[i].clear(mf, indexes, lis); + for (Entry &E : Entries) + E.clear(mf, indexes, lis); } InterferenceCache::Entry *InterferenceCache::get(MCRegister PhysReg) { diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp index cf62b0e5d7e8..e97dcca201e8 100644 --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp @@ -1249,8 +1249,8 @@ bool InstrRefBasedLDV::transferDebugPHI(MachineInstr &MI) { std::array CandidateSizes = {64, 32, 16, 8}; Optional Result = None; Optional SpillLoc = None; - for (unsigned int I = 0; I < CandidateSizes.size(); ++I) { - unsigned SpillID = MTracker->getLocID(SpillNo, {CandidateSizes[I], 0}); + for (unsigned CS : CandidateSizes) { + unsigned SpillID = MTracker->getLocID(SpillNo, {CS, 0}); SpillLoc = MTracker->getSpillMLoc(SpillID); ValueIDNum Val = MTracker->readMLoc(*SpillLoc); // If this value was defined in it's own position, then it was probably diff --git a/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp index a632d3d9ce76..b4dd41bbb810 100644 --- a/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp @@ -492,10 +492,10 @@ private: static VarLoc CreateCopyLoc(const VarLoc &OldVL, const MachineLoc &OldML, Register NewReg) { VarLoc VL = OldVL; - for (size_t I = 0, E = VL.Locs.size(); I < E; ++I) - if (VL.Locs[I] == OldML) { - VL.Locs[I].Kind = MachineLocKind::RegisterKind; - VL.Locs[I].Value.RegNo = NewReg; + for (MachineLoc &ML : VL.Locs) + if (ML == OldML) { + ML.Kind = MachineLocKind::RegisterKind; + ML.Value.RegNo = NewReg; return VL; } llvm_unreachable("Should have found OldML in new VarLoc."); @@ -506,10 +506,10 @@ private: static VarLoc CreateSpillLoc(const VarLoc &OldVL, const MachineLoc &OldML, unsigned SpillBase, StackOffset SpillOffset) { VarLoc VL = OldVL; - for (int I = 0, E = VL.Locs.size(); I < E; ++I) - if (VL.Locs[I] == OldML) { - VL.Locs[I].Kind = MachineLocKind::SpillLocKind; - VL.Locs[I].Value.SpillLocation = {SpillBase, SpillOffset}; + for (MachineLoc &ML : VL.Locs) + if (ML == OldML) { + ML.Kind = MachineLocKind::SpillLocKind; + ML.Value.SpillLocation = {SpillBase, SpillOffset}; return VL; } llvm_unreachable("Should have found OldML in new VarLoc."); diff --git a/llvm/lib/CodeGen/LiveDebugVariables.cpp b/llvm/lib/CodeGen/LiveDebugVariables.cpp index 5f976bf43c5b..e6661e5135c3 100644 --- a/llvm/lib/CodeGen/LiveDebugVariables.cpp +++ b/llvm/lib/CodeGen/LiveDebugVariables.cpp @@ -822,9 +822,6 @@ bool LDVImpl::handleDebugValue(MachineInstr &MI, SlotIndex Idx) { // register that hasn't been defined yet. If we do not remove those here, then // the re-insertion of the DBG_VALUE instruction after register allocation // will be incorrect. - // TODO: If earlier passes are corrected to generate sane debug information - // (and if the machine verifier is improved to catch this), then these checks - // could be removed or replaced by asserts. bool Discard = false; for (const MachineOperand &Op : MI.debug_operands()) { if (Op.isReg() && Register::isVirtualRegister(Op.getReg())) { @@ -1341,8 +1338,8 @@ UserValue::splitLocation(unsigned OldLocNo, ArrayRef NewRegs, bool DidChange = false; LocMap::iterator LocMapI; LocMapI.setMap(locInts); - for (unsigned i = 0; i != NewRegs.size(); ++i) { - LiveInterval *LI = &LIS.getInterval(NewRegs[i]); + for (Register NewReg : NewRegs) { + LiveInterval *LI = &LIS.getInterval(NewReg); if (LI->empty()) continue; @@ -1500,8 +1497,8 @@ void LDVImpl::splitRegister(Register OldReg, ArrayRef NewRegs) { // Map all of the new virtual registers. UserValue *UV = lookupVirtReg(OldReg); - for (unsigned i = 0; i != NewRegs.size(); ++i) - mapVirtReg(NewRegs[i], UV); + for (Register NewReg : NewRegs) + mapVirtReg(NewReg, UV); } void LiveDebugVariables:: diff --git a/llvm/lib/CodeGen/LiveDebugVariables.h b/llvm/lib/CodeGen/LiveDebugVariables.h index 07dd3a83866f..9998ce9e8dad 100644 --- a/llvm/lib/CodeGen/LiveDebugVariables.h +++ b/llvm/lib/CodeGen/LiveDebugVariables.h @@ -56,6 +56,11 @@ private: bool runOnMachineFunction(MachineFunction &) override; void releaseMemory() override; void getAnalysisUsage(AnalysisUsage &) const override; + + MachineFunctionProperties getSetProperties() const override { + return MachineFunctionProperties().set( + MachineFunctionProperties::Property::TracksDebugUserValues); + } }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/LiveRangeEdit.cpp b/llvm/lib/CodeGen/LiveRangeEdit.cpp index 6380c4bfd6e6..05768140cbdf 100644 --- a/llvm/lib/CodeGen/LiveRangeEdit.cpp +++ b/llvm/lib/CodeGen/LiveRangeEdit.cpp @@ -133,6 +133,22 @@ bool LiveRangeEdit::allUsesAvailableAt(const MachineInstr *OrigMI, if (OVNI != li.getVNInfoAt(UseIdx)) return false; + + // Check that subrange is live at UseIdx. + if (MO.getSubReg()) { + const TargetRegisterInfo *TRI = MRI.getTargetRegisterInfo(); + LaneBitmask LM = TRI->getSubRegIndexLaneMask(MO.getSubReg()); + for (LiveInterval::SubRange &SR : li.subranges()) { + if ((SR.LaneMask & LM).none()) + continue; + if (!SR.liveAt(UseIdx)) + return false; + // Early exit if all used lanes are checked. No need to continue. + LM &= ~SR.LaneMask; + if (LM.none()) + break; + } + } } return true; } diff --git a/llvm/lib/CodeGen/LiveVariables.cpp b/llvm/lib/CodeGen/LiveVariables.cpp index e8744797707b..94bdfab5e5e0 100644 --- a/llvm/lib/CodeGen/LiveVariables.cpp +++ b/llvm/lib/CodeGen/LiveVariables.cpp @@ -141,8 +141,8 @@ void LiveVariables::HandleVirtRegUse(Register Reg, MachineBasicBlock *MBB, } #ifndef NDEBUG - for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i) - assert(VRInfo.Kills[i]->getParent() != MBB && "entry should be at end!"); + for (MachineInstr *Kill : VRInfo.Kills) + assert(Kill->getParent() != MBB && "entry should be at end!"); #endif // This situation can occur: @@ -534,8 +534,7 @@ void LiveVariables::runOnInstr(MachineInstr &MI, MachineBasicBlock *MBB = MI.getParent(); // Process all uses. - for (unsigned i = 0, e = UseRegs.size(); i != e; ++i) { - unsigned MOReg = UseRegs[i]; + for (unsigned MOReg : UseRegs) { if (Register::isVirtualRegister(MOReg)) HandleVirtRegUse(MOReg, MBB, MI); else if (!MRI->isReserved(MOReg)) @@ -543,12 +542,11 @@ void LiveVariables::runOnInstr(MachineInstr &MI, } // Process all masked registers. (Call clobbers). - for (unsigned i = 0, e = RegMasks.size(); i != e; ++i) - HandleRegMask(MI.getOperand(RegMasks[i])); + for (unsigned Mask : RegMasks) + HandleRegMask(MI.getOperand(Mask)); // Process all defs. - for (unsigned i = 0, e = DefRegs.size(); i != e; ++i) { - unsigned MOReg = DefRegs[i]; + for (unsigned MOReg : DefRegs) { if (Register::isVirtualRegister(MOReg)) HandleVirtRegDef(MOReg, MI); else if (!MRI->isReserved(MOReg)) diff --git a/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp b/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp index ee2387d1e8e6..37fd3e4853ac 100644 --- a/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp +++ b/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp @@ -210,7 +210,11 @@ void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) { StackObjSet SmallArrayObjs; StackObjSet AddrOfObjs; - AdjustStackOffset(MFI, StackProtectorFI, Offset, StackGrowsDown, MaxAlign); + // Only place the stack protector in the local stack area if the target + // allows it. + if (TFI.isStackIdSafeForLocalArea(MFI.getStackID(StackProtectorFI))) + AdjustStackOffset(MFI, StackProtectorFI, Offset, StackGrowsDown, + MaxAlign); // Assign large stack objects first. for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) { diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp index 6221b5929301..d0323eaf3d78 100644 --- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp @@ -350,18 +350,33 @@ void MIRParserImpl::computeFunctionProperties(MachineFunction &MF) { bool HasPHI = false; bool HasInlineAsm = false; + bool AllTiedOpsRewritten = true, HasTiedOps = false; for (const MachineBasicBlock &MBB : MF) { for (const MachineInstr &MI : MBB) { if (MI.isPHI()) HasPHI = true; if (MI.isInlineAsm()) HasInlineAsm = true; + for (unsigned I = 0; I < MI.getNumOperands(); ++I) { + const MachineOperand &MO = MI.getOperand(I); + if (!MO.isReg() || !MO.getReg()) + continue; + unsigned DefIdx; + if (MO.isUse() && MI.isRegTiedToDefOperand(I, &DefIdx)) { + HasTiedOps = true; + if (MO.getReg() != MI.getOperand(DefIdx).getReg()) + AllTiedOpsRewritten = false; + } + } } } if (!HasPHI) Properties.set(MachineFunctionProperties::Property::NoPHIs); MF.setHasInlineAsm(HasInlineAsm); + if (HasTiedOps && AllTiedOpsRewritten) + Properties.set(MachineFunctionProperties::Property::TiedOpsRewritten); + if (isSSA(MF)) Properties.set(MachineFunctionProperties::Property::IsSSA); else @@ -457,6 +472,9 @@ MIRParserImpl::initializeMachineFunction(const yaml::MachineFunction &YamlMF, if (YamlMF.FailsVerification) MF.getProperties().set( MachineFunctionProperties::Property::FailsVerification); + if (YamlMF.TracksDebugUserValues) + MF.getProperties().set( + MachineFunctionProperties::Property::TracksDebugUserValues); PerFunctionMIParsingState PFS(MF, SM, IRSlots, *Target); if (parseRegisterInfo(PFS, YamlMF)) diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp index f1369396e37f..dc72f83ad0e4 100644 --- a/llvm/lib/CodeGen/MIRPrinter.cpp +++ b/llvm/lib/CodeGen/MIRPrinter.cpp @@ -219,6 +219,8 @@ void MIRPrinter::print(const MachineFunction &MF) { MachineFunctionProperties::Property::FailedISel); YamlMF.FailsVerification = MF.getProperties().hasProperty( MachineFunctionProperties::Property::FailsVerification); + YamlMF.TracksDebugUserValues = MF.getProperties().hasProperty( + MachineFunctionProperties::Property::TracksDebugUserValues); convert(YamlMF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo()); MachineModuleSlotTracker MST(&MF); diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp index 23c511aaa056..8c9d00d08c6a 100644 --- a/llvm/lib/CodeGen/MachineBasicBlock.cpp +++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp @@ -193,7 +193,7 @@ void ilist_traits::transferNodesFromList(ilist_traits &FromList, void ilist_traits::deleteNode(MachineInstr *MI) { assert(!MI->getParent() && "MI is still in a block!"); - Parent->getParent()->DeleteMachineInstr(MI); + Parent->getParent()->deleteMachineInstr(MI); } MachineBasicBlock::iterator MachineBasicBlock::getFirstNonPHI() { @@ -1038,16 +1038,15 @@ MachineBasicBlock *MachineBasicBlock::SplitCriticalEdge( // Collect a list of virtual registers killed by the terminators. SmallVector KilledRegs; if (LV) - for (instr_iterator I = getFirstInstrTerminator(), E = instr_end(); - I != E; ++I) { - MachineInstr *MI = &*I; - for (MachineOperand &MO : MI->operands()) { + for (MachineInstr &MI : + llvm::make_range(getFirstInstrTerminator(), instr_end())) { + for (MachineOperand &MO : MI.operands()) { if (!MO.isReg() || MO.getReg() == 0 || !MO.isUse() || !MO.isKill() || MO.isUndef()) continue; Register Reg = MO.getReg(); if (Register::isPhysicalRegister(Reg) || - LV->getVarInfo(Reg).removeKill(*MI)) { + LV->getVarInfo(Reg).removeKill(MI)) { KilledRegs.push_back(Reg); LLVM_DEBUG(dbgs() << "Removing terminator kill: " << MI); MO.setIsKill(false); @@ -1057,11 +1056,9 @@ MachineBasicBlock *MachineBasicBlock::SplitCriticalEdge( SmallVector UsedRegs; if (LIS) { - for (instr_iterator I = getFirstInstrTerminator(), E = instr_end(); - I != E; ++I) { - MachineInstr *MI = &*I; - - for (const MachineOperand &MO : MI->operands()) { + for (MachineInstr &MI : + llvm::make_range(getFirstInstrTerminator(), instr_end())) { + for (const MachineOperand &MO : MI.operands()) { if (!MO.isReg() || MO.getReg() == 0) continue; @@ -1078,9 +1075,9 @@ MachineBasicBlock *MachineBasicBlock::SplitCriticalEdge( // SlotIndexes. SmallVector Terminators; if (Indexes) { - for (instr_iterator I = getFirstInstrTerminator(), E = instr_end(); - I != E; ++I) - Terminators.push_back(&*I); + for (MachineInstr &MI : + llvm::make_range(getFirstInstrTerminator(), instr_end())) + Terminators.push_back(&MI); } // Since we replaced all uses of Succ with NMBB, that should also be treated @@ -1091,9 +1088,9 @@ MachineBasicBlock *MachineBasicBlock::SplitCriticalEdge( if (Indexes) { SmallVector NewTerminators; - for (instr_iterator I = getFirstInstrTerminator(), E = instr_end(); - I != E; ++I) - NewTerminators.push_back(&*I); + for (MachineInstr &MI : + llvm::make_range(getFirstInstrTerminator(), instr_end())) + NewTerminators.push_back(&MI); for (MachineInstr *Terminator : Terminators) { if (!is_contained(NewTerminators, Terminator)) diff --git a/llvm/lib/CodeGen/MachineBlockPlacement.cpp b/llvm/lib/CodeGen/MachineBlockPlacement.cpp index 8a1b4031642d..692587cd58fa 100644 --- a/llvm/lib/CodeGen/MachineBlockPlacement.cpp +++ b/llvm/lib/CodeGen/MachineBlockPlacement.cpp @@ -61,6 +61,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Utils/CodeLayout.h" #include #include #include @@ -193,6 +194,11 @@ static cl::opt TriangleChainCount( cl::init(2), cl::Hidden); +static cl::opt EnableExtTspBlockPlacement( + "enable-ext-tsp-block-placement", cl::Hidden, cl::init(false), + cl::desc("Enable machine block placement based on the ext-tsp model, " + "optimizing I-cache utilization.")); + namespace llvm { extern cl::opt StaticLikelyProb; extern cl::opt ProfileLikelyProb; @@ -557,6 +563,15 @@ class MachineBlockPlacement : public MachineFunctionPass { /// but a local analysis would not find them. void precomputeTriangleChains(); + /// Apply a post-processing step optimizing block placement. + void applyExtTsp(); + + /// Modify the existing block placement in the function and adjust all jumps. + void assignBlockOrder(const std::vector &NewOrder); + + /// Create a single CFG chain from the current block order. + void createCFGChainExtTsp(); + public: static char ID; // Pass identification, replacement for typeid @@ -3387,6 +3402,15 @@ bool MachineBlockPlacement::runOnMachineFunction(MachineFunction &MF) { } } + // Apply a post-processing optimizing block placement. + if (MF.size() >= 3 && EnableExtTspBlockPlacement) { + // Find a new placement and modify the layout of the blocks in the function. + applyExtTsp(); + + // Re-create CFG chain so that we can optimizeBranches and alignBlocks. + createCFGChainExtTsp(); + } + optimizeBranches(); alignBlocks(); @@ -3413,12 +3437,147 @@ bool MachineBlockPlacement::runOnMachineFunction(MachineFunction &MF) { MBFI->view("MBP." + MF.getName(), false); } - // We always return true as we have no way to track whether the final order // differs from the original order. return true; } +void MachineBlockPlacement::applyExtTsp() { + // Prepare data; blocks are indexed by their index in the current ordering. + DenseMap BlockIndex; + BlockIndex.reserve(F->size()); + std::vector CurrentBlockOrder; + CurrentBlockOrder.reserve(F->size()); + size_t NumBlocks = 0; + for (const MachineBasicBlock &MBB : *F) { + BlockIndex[&MBB] = NumBlocks++; + CurrentBlockOrder.push_back(&MBB); + } + + auto BlockSizes = std::vector(F->size()); + auto BlockCounts = std::vector(F->size()); + DenseMap, uint64_t> JumpCounts; + for (MachineBasicBlock &MBB : *F) { + // Getting the block frequency. + BlockFrequency BlockFreq = MBFI->getBlockFreq(&MBB); + BlockCounts[BlockIndex[&MBB]] = BlockFreq.getFrequency(); + // Getting the block size: + // - approximate the size of an instruction by 4 bytes, and + // - ignore debug instructions. + // Note: getting the exact size of each block is target-dependent and can be + // done by extending the interface of MCCodeEmitter. Experimentally we do + // not see a perf improvement with the exact block sizes. + auto NonDbgInsts = + instructionsWithoutDebug(MBB.instr_begin(), MBB.instr_end()); + int NumInsts = std::distance(NonDbgInsts.begin(), NonDbgInsts.end()); + BlockSizes[BlockIndex[&MBB]] = 4 * NumInsts; + // Getting jump frequencies. + for (MachineBasicBlock *Succ : MBB.successors()) { + auto EP = MBPI->getEdgeProbability(&MBB, Succ); + BlockFrequency EdgeFreq = BlockFreq * EP; + auto Edge = std::make_pair(BlockIndex[&MBB], BlockIndex[Succ]); + JumpCounts[Edge] = EdgeFreq.getFrequency(); + } + } + + LLVM_DEBUG(dbgs() << "Applying ext-tsp layout for |V| = " << F->size() + << " with profile = " << F->getFunction().hasProfileData() + << " (" << F->getName().str() << ")" + << "\n"); + LLVM_DEBUG( + dbgs() << format(" original layout score: %0.2f\n", + calcExtTspScore(BlockSizes, BlockCounts, JumpCounts))); + + // Run the layout algorithm. + auto NewOrder = applyExtTspLayout(BlockSizes, BlockCounts, JumpCounts); + std::vector NewBlockOrder; + NewBlockOrder.reserve(F->size()); + for (uint64_t Node : NewOrder) { + NewBlockOrder.push_back(CurrentBlockOrder[Node]); + } + LLVM_DEBUG(dbgs() << format(" optimized layout score: %0.2f\n", + calcExtTspScore(NewOrder, BlockSizes, BlockCounts, + JumpCounts))); + + // Assign new block order. + assignBlockOrder(NewBlockOrder); +} + +void MachineBlockPlacement::assignBlockOrder( + const std::vector &NewBlockOrder) { + assert(F->size() == NewBlockOrder.size() && "Incorrect size of block order"); + F->RenumberBlocks(); + + bool HasChanges = false; + for (size_t I = 0; I < NewBlockOrder.size(); I++) { + if (NewBlockOrder[I] != F->getBlockNumbered(I)) { + HasChanges = true; + break; + } + } + // Stop early if the new block order is identical to the existing one. + if (!HasChanges) + return; + + SmallVector PrevFallThroughs(F->getNumBlockIDs()); + for (auto &MBB : *F) { + PrevFallThroughs[MBB.getNumber()] = MBB.getFallThrough(); + } + + // Sort basic blocks in the function according to the computed order. + DenseMap NewIndex; + for (const MachineBasicBlock *MBB : NewBlockOrder) { + NewIndex[MBB] = NewIndex.size(); + } + F->sort([&](MachineBasicBlock &L, MachineBasicBlock &R) { + return NewIndex[&L] < NewIndex[&R]; + }); + + // Update basic block branches by inserting explicit fallthrough branches + // when required and re-optimize branches when possible. + const TargetInstrInfo *TII = F->getSubtarget().getInstrInfo(); + SmallVector Cond; + for (auto &MBB : *F) { + MachineFunction::iterator NextMBB = std::next(MBB.getIterator()); + MachineFunction::iterator EndIt = MBB.getParent()->end(); + auto *FTMBB = PrevFallThroughs[MBB.getNumber()]; + // If this block had a fallthrough before we need an explicit unconditional + // branch to that block if the fallthrough block is not adjacent to the + // block in the new order. + if (FTMBB && (NextMBB == EndIt || &*NextMBB != FTMBB)) { + TII->insertUnconditionalBranch(MBB, FTMBB, MBB.findBranchDebugLoc()); + } + + // It might be possible to optimize branches by flipping the condition. + Cond.clear(); + MachineBasicBlock *TBB = nullptr, *FBB = nullptr; + if (TII->analyzeBranch(MBB, TBB, FBB, Cond)) + continue; + MBB.updateTerminator(FTMBB); + } + +#ifndef NDEBUG + // Make sure we correctly constructed all branches. + F->verify(this, "After optimized block reordering"); +#endif +} + +void MachineBlockPlacement::createCFGChainExtTsp() { + BlockToChain.clear(); + ComputedEdges.clear(); + ChainAllocator.DestroyAll(); + + MachineBasicBlock *HeadBB = &F->front(); + BlockChain *FunctionChain = + new (ChainAllocator.Allocate()) BlockChain(BlockToChain, HeadBB); + + for (MachineBasicBlock &MBB : *F) { + if (HeadBB == &MBB) + continue; // Ignore head of the chain + FunctionChain->merge(&MBB, nullptr); + } +} + namespace { /// A pass to compute block placement statistics. diff --git a/llvm/lib/CodeGen/MachineCombiner.cpp b/llvm/lib/CodeGen/MachineCombiner.cpp index e2b6cfe55c16..72ab9ee4f388 100644 --- a/llvm/lib/CodeGen/MachineCombiner.cpp +++ b/llvm/lib/CodeGen/MachineCombiner.cpp @@ -485,7 +485,7 @@ static void insertDeleteInstructions(MachineBasicBlock *MBB, MachineInstr &MI, MBB->insert((MachineBasicBlock::iterator)&MI, InstrPtr); for (auto *InstrPtr : DelInstrs) { - InstrPtr->eraseFromParentAndMarkDBGValuesForRemoval(); + InstrPtr->eraseFromParent(); // Erase all LiveRegs defined by the removed instruction for (auto I = RegUnits.begin(); I != RegUnits.end(); ) { if (I->MI == InstrPtr) @@ -693,7 +693,7 @@ bool MachineCombiner::combineInstructions(MachineBasicBlock *MBB) { // use for them. MachineFunction *MF = MBB->getParent(); for (auto *InstrPtr : InsInstrs) - MF->DeleteMachineInstr(InstrPtr); + MF->deleteMachineInstr(InstrPtr); } InstrIdxForVirtReg.clear(); } diff --git a/llvm/lib/CodeGen/MachineCopyPropagation.cpp b/llvm/lib/CodeGen/MachineCopyPropagation.cpp index 7c83bacd80d9..57fbe4112e47 100644 --- a/llvm/lib/CodeGen/MachineCopyPropagation.cpp +++ b/llvm/lib/CodeGen/MachineCopyPropagation.cpp @@ -847,31 +847,27 @@ void MachineCopyPropagation::BackwardCopyPropagateBlock( LLVM_DEBUG(dbgs() << "MCP: BackwardCopyPropagateBlock " << MBB.getName() << "\n"); - for (MachineBasicBlock::reverse_iterator I = MBB.rbegin(), E = MBB.rend(); - I != E;) { - MachineInstr *MI = &*I; - ++I; - + for (MachineInstr &MI : llvm::make_early_inc_range(llvm::reverse(MBB))) { // Ignore non-trivial COPYs. - if (MI->isCopy() && MI->getNumOperands() == 2 && - !TRI->regsOverlap(MI->getOperand(0).getReg(), - MI->getOperand(1).getReg())) { + if (MI.isCopy() && MI.getNumOperands() == 2 && + !TRI->regsOverlap(MI.getOperand(0).getReg(), + MI.getOperand(1).getReg())) { - MCRegister Def = MI->getOperand(0).getReg().asMCReg(); - MCRegister Src = MI->getOperand(1).getReg().asMCReg(); + MCRegister Def = MI.getOperand(0).getReg().asMCReg(); + MCRegister Src = MI.getOperand(1).getReg().asMCReg(); // Unlike forward cp, we don't invoke propagateDefs here, // just let forward cp do COPY-to-COPY propagation. - if (isBackwardPropagatableCopy(*MI, *MRI)) { + if (isBackwardPropagatableCopy(MI, *MRI)) { Tracker.invalidateRegister(Src, *TRI); Tracker.invalidateRegister(Def, *TRI); - Tracker.trackCopy(MI, *TRI); + Tracker.trackCopy(&MI, *TRI); continue; } } // Invalidate any earlyclobber regs first. - for (const MachineOperand &MO : MI->operands()) + for (const MachineOperand &MO : MI.operands()) if (MO.isReg() && MO.isEarlyClobber()) { MCRegister Reg = MO.getReg().asMCReg(); if (!Reg) @@ -879,8 +875,8 @@ void MachineCopyPropagation::BackwardCopyPropagateBlock( Tracker.invalidateRegister(Reg, *TRI); } - propagateDefs(*MI); - for (const MachineOperand &MO : MI->operands()) { + propagateDefs(MI); + for (const MachineOperand &MO : MI.operands()) { if (!MO.isReg()) continue; @@ -898,7 +894,7 @@ void MachineCopyPropagation::BackwardCopyPropagateBlock( for (MCRegUnitIterator RUI(MO.getReg().asMCReg(), TRI); RUI.isValid(); ++RUI) { if (auto *Copy = Tracker.findCopyDefViaUnit(*RUI, *TRI)) { - CopyDbgUsers[Copy].insert(MI); + CopyDbgUsers[Copy].insert(&MI); } } } else { diff --git a/llvm/lib/CodeGen/MachineCycleAnalysis.cpp b/llvm/lib/CodeGen/MachineCycleAnalysis.cpp new file mode 100644 index 000000000000..42a5e2b7af01 --- /dev/null +++ b/llvm/lib/CodeGen/MachineCycleAnalysis.cpp @@ -0,0 +1,113 @@ +//===- MachineCycleAnalysis.cpp - Compute CycleInfo for Machine IR --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineCycleAnalysis.h" +#include "llvm/ADT/GenericCycleImpl.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineSSAContext.h" +#include "llvm/InitializePasses.h" + +using namespace llvm; + +template class llvm::GenericCycleInfo; +template class llvm::GenericCycle; + +namespace { + +/// Legacy analysis pass which computes a \ref MachineCycleInfo. +class MachineCycleInfoWrapperPass : public MachineFunctionPass { + MachineFunction *F = nullptr; + MachineCycleInfo CI; + +public: + static char ID; + + MachineCycleInfoWrapperPass(); + + MachineCycleInfo &getCycleInfo() { return CI; } + const MachineCycleInfo &getCycleInfo() const { return CI; } + + bool runOnMachineFunction(MachineFunction &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; + void releaseMemory() override; + void print(raw_ostream &OS, const Module *M = nullptr) const override; + + // TODO: verify analysis +}; + +class MachineCycleInfoPrinterPass : public MachineFunctionPass { +public: + static char ID; + + MachineCycleInfoPrinterPass(); + + bool runOnMachineFunction(MachineFunction &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +} // namespace + +char MachineCycleInfoWrapperPass::ID = 0; + +MachineCycleInfoWrapperPass::MachineCycleInfoWrapperPass() + : MachineFunctionPass(ID) { + initializeMachineCycleInfoWrapperPassPass(*PassRegistry::getPassRegistry()); +} + +INITIALIZE_PASS_BEGIN(MachineCycleInfoWrapperPass, "machine-cycles", + "Machine Cycle Info Analysis", true, true) +INITIALIZE_PASS_END(MachineCycleInfoWrapperPass, "machine-cycles", + "Machine Cycle Info Analysis", true, true) + +void MachineCycleInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +bool MachineCycleInfoWrapperPass::runOnMachineFunction(MachineFunction &Func) { + CI.clear(); + + F = &Func; + CI.compute(Func); + return false; +} + +void MachineCycleInfoWrapperPass::print(raw_ostream &OS, const Module *) const { + OS << "MachineCycleInfo for function: " << F->getName() << "\n"; + CI.print(OS); +} + +void MachineCycleInfoWrapperPass::releaseMemory() { + CI.clear(); + F = nullptr; +} + +char MachineCycleInfoPrinterPass::ID = 0; + +MachineCycleInfoPrinterPass::MachineCycleInfoPrinterPass() + : MachineFunctionPass(ID) { + initializeMachineCycleInfoPrinterPassPass(*PassRegistry::getPassRegistry()); +} + +INITIALIZE_PASS_BEGIN(MachineCycleInfoPrinterPass, "print-machine-cycles", + "Print Machine Cycle Info Analysis", true, true) +INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass) +INITIALIZE_PASS_END(MachineCycleInfoPrinterPass, "print-machine-cycles", + "Print Machine Cycle Info Analysis", true, true) + +void MachineCycleInfoPrinterPass::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +bool MachineCycleInfoPrinterPass::runOnMachineFunction(MachineFunction &F) { + auto &CI = getAnalysis(); + CI.print(errs()); + return false; +} diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp index 310c2721c3bd..81ed3d0e93ff 100644 --- a/llvm/lib/CodeGen/MachineFunction.cpp +++ b/llvm/lib/CodeGen/MachineFunction.cpp @@ -89,6 +89,7 @@ static cl::opt AlignAllFunctions( static const char *getPropertyName(MachineFunctionProperties::Property Prop) { using P = MachineFunctionProperties::Property; + // clang-format off switch(Prop) { case P::FailedISel: return "FailedISel"; case P::IsSSA: return "IsSSA"; @@ -100,7 +101,9 @@ static const char *getPropertyName(MachineFunctionProperties::Property Prop) { case P::TracksLiveness: return "TracksLiveness"; case P::TiedOpsRewritten: return "TiedOpsRewritten"; case P::FailsVerification: return "FailsVerification"; + case P::TracksDebugUserValues: return "TracksDebugUserValues"; } + // clang-format on llvm_unreachable("Invalid machine function property"); } @@ -125,7 +128,7 @@ void MachineFunctionProperties::print(raw_ostream &OS) const { MachineFunctionInfo::~MachineFunctionInfo() = default; void ilist_alloc_traits::deleteNode(MachineBasicBlock *MBB) { - MBB->getParent()->DeleteMachineBasicBlock(MBB); + MBB->getParent()->deleteMachineBasicBlock(MBB); } static inline unsigned getFnStackAlignment(const TargetSubtargetInfo *STI, @@ -347,10 +350,10 @@ void MachineFunction::assignBeginEndSections() { /// Allocate a new MachineInstr. Use this instead of `new MachineInstr'. MachineInstr *MachineFunction::CreateMachineInstr(const MCInstrDesc &MCID, - const DebugLoc &DL, + DebugLoc DL, bool NoImplicit) { return new (InstructionRecycler.Allocate(Allocator)) - MachineInstr(*this, MCID, DL, NoImplicit); + MachineInstr(*this, MCID, std::move(DL), NoImplicit); } /// Create a new MachineInstr which is a copy of the 'Orig' instruction, @@ -361,8 +364,9 @@ MachineFunction::CloneMachineInstr(const MachineInstr *Orig) { MachineInstr(*this, *Orig); } -MachineInstr &MachineFunction::CloneMachineInstrBundle(MachineBasicBlock &MBB, - MachineBasicBlock::iterator InsertBefore, const MachineInstr &Orig) { +MachineInstr &MachineFunction::cloneMachineInstrBundle( + MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore, + const MachineInstr &Orig) { MachineInstr *FirstClone = nullptr; MachineBasicBlock::const_instr_iterator I = Orig.getIterator(); while (true) { @@ -390,8 +394,7 @@ MachineInstr &MachineFunction::CloneMachineInstrBundle(MachineBasicBlock &MBB, /// /// This function also serves as the MachineInstr destructor - the real /// ~MachineInstr() destructor must be empty. -void -MachineFunction::DeleteMachineInstr(MachineInstr *MI) { +void MachineFunction::deleteMachineInstr(MachineInstr *MI) { // Verify that a call site info is at valid state. This assertion should // be triggered during the implementation of support for the // call site info of a new architecture. If the assertion is triggered, @@ -418,8 +421,7 @@ MachineFunction::CreateMachineBasicBlock(const BasicBlock *bb) { } /// Delete the given MachineBasicBlock. -void -MachineFunction::DeleteMachineBasicBlock(MachineBasicBlock *MBB) { +void MachineFunction::deleteMachineBasicBlock(MachineBasicBlock *MBB) { assert(MBB->getParent() == this && "MBB parent mismatch!"); // Clean up any references to MBB in jump tables before deleting it. if (JumpTableInfo) @@ -769,8 +771,8 @@ MCSymbol *MachineFunction::addLandingPad(MachineBasicBlock *LandingPad) { void MachineFunction::addCatchTypeInfo(MachineBasicBlock *LandingPad, ArrayRef TyInfo) { LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad); - for (unsigned N = TyInfo.size(); N; --N) - LP.TypeIds.push_back(getTypeIDFor(TyInfo[N - 1])); + for (const GlobalValue *GV : llvm::reverse(TyInfo)) + LP.TypeIds.push_back(getTypeIDFor(GV)); } void MachineFunction::addFilterTypeInfo(MachineBasicBlock *LandingPad, @@ -1404,10 +1406,10 @@ MachineConstantPool::~MachineConstantPool() { // A constant may be a member of both Constants and MachineCPVsSharingEntries, // so keep track of which we've deleted to avoid double deletions. DenseSet Deleted; - for (unsigned i = 0, e = Constants.size(); i != e; ++i) - if (Constants[i].isMachineConstantPoolEntry()) { - Deleted.insert(Constants[i].Val.MachineCPVal); - delete Constants[i].Val.MachineCPVal; + for (const MachineConstantPoolEntry &C : Constants) + if (C.isMachineConstantPoolEntry()) { + Deleted.insert(C.Val.MachineCPVal); + delete C.Val.MachineCPVal; } for (MachineConstantPoolValue *CPV : MachineCPVsSharingEntries) { if (Deleted.count(CPV) == 0) diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp index aaa80432d2f2..85b266afceef 100644 --- a/llvm/lib/CodeGen/MachineInstr.cpp +++ b/llvm/lib/CodeGen/MachineInstr.cpp @@ -115,10 +115,10 @@ void MachineInstr::addImplicitDefUseOperands(MachineFunction &MF) { /// MachineInstr ctor - This constructor creates a MachineInstr and adds the /// implicit operands. It reserves space for the number of operands specified by /// the MCInstrDesc. -MachineInstr::MachineInstr(MachineFunction &MF, const MCInstrDesc &tid, - DebugLoc dl, bool NoImp) - : MCID(&tid), debugLoc(std::move(dl)), DebugInstrNum(0) { - assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor"); +MachineInstr::MachineInstr(MachineFunction &MF, const MCInstrDesc &TID, + DebugLoc DL, bool NoImp) + : MCID(&TID), DbgLoc(std::move(DL)), DebugInstrNum(0) { + assert(DbgLoc.hasTrivialDestructor() && "Expected trivial destructor"); // Reserve space for the expected number of operands. if (unsigned NumOps = MCID->getNumOperands() + @@ -135,9 +135,9 @@ MachineInstr::MachineInstr(MachineFunction &MF, const MCInstrDesc &tid, /// Does not copy the number from debug instruction numbering, to preserve /// uniqueness. MachineInstr::MachineInstr(MachineFunction &MF, const MachineInstr &MI) - : MCID(&MI.getDesc()), Info(MI.Info), debugLoc(MI.getDebugLoc()), + : MCID(&MI.getDesc()), Info(MI.Info), DbgLoc(MI.getDebugLoc()), DebugInstrNum(0) { - assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor"); + assert(DbgLoc.hasTrivialDestructor() && "Expected trivial destructor"); CapOperands = OperandCapacity::get(MI.getNumOperands()); Operands = MF.allocateOperandArray(CapOperands); @@ -682,26 +682,6 @@ void MachineInstr::eraseFromParent() { getParent()->erase(this); } -void MachineInstr::eraseFromParentAndMarkDBGValuesForRemoval() { - assert(getParent() && "Not embedded in a basic block!"); - MachineBasicBlock *MBB = getParent(); - MachineFunction *MF = MBB->getParent(); - assert(MF && "Not embedded in a function!"); - - MachineInstr *MI = (MachineInstr *)this; - MachineRegisterInfo &MRI = MF->getRegInfo(); - - for (const MachineOperand &MO : MI->operands()) { - if (!MO.isReg() || !MO.isDef()) - continue; - Register Reg = MO.getReg(); - if (!Reg.isVirtual()) - continue; - MRI.markUsesInDebugValueAsUndef(Reg); - } - MI->eraseFromParent(); -} - void MachineInstr::eraseFromBundle() { assert(getParent() && "Not embedded in a basic block!"); getParent()->erase_instr(this); diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp index 8d6459a627fa..762395542b40 100644 --- a/llvm/lib/CodeGen/MachinePipeliner.cpp +++ b/llvm/lib/CodeGen/MachinePipeliner.cpp @@ -649,7 +649,7 @@ void SwingSchedulerDAG::schedule() { /// Clean up after the software pipeliner runs. void SwingSchedulerDAG::finishBlock() { for (auto &KV : NewMIs) - MF.DeleteMachineInstr(KV.second); + MF.deleteMachineInstr(KV.second); NewMIs.clear(); // Call the superclass. @@ -1101,17 +1101,15 @@ unsigned SwingSchedulerDAG::calculateResMII() { // Sort the instructions by the number of available choices for scheduling, // least to most. Use the number of critical resources as the tie breaker. FuncUnitSorter FUS = FuncUnitSorter(MF.getSubtarget()); - for (MachineBasicBlock::iterator I = MBB->getFirstNonPHI(), - E = MBB->getFirstTerminator(); - I != E; ++I) - FUS.calcCriticalResources(*I); + for (MachineInstr &MI : + llvm::make_range(MBB->getFirstNonPHI(), MBB->getFirstTerminator())) + FUS.calcCriticalResources(MI); PriorityQueue, FuncUnitSorter> FuncUnitOrder(FUS); - for (MachineBasicBlock::iterator I = MBB->getFirstNonPHI(), - E = MBB->getFirstTerminator(); - I != E; ++I) - FuncUnitOrder.push(&*I); + for (MachineInstr &MI : + llvm::make_range(MBB->getFirstNonPHI(), MBB->getFirstTerminator())) + FuncUnitOrder.push(&MI); while (!FuncUnitOrder.empty()) { MachineInstr *MI = FuncUnitOrder.top(); @@ -1192,14 +1190,10 @@ unsigned SwingSchedulerDAG::calculateRecMII(NodeSetType &NodeSets) { /// but we do this to find the circuits, and then change them back. static void swapAntiDependences(std::vector &SUnits) { SmallVector, 8> DepsAdded; - for (unsigned i = 0, e = SUnits.size(); i != e; ++i) { - SUnit *SU = &SUnits[i]; - for (SUnit::pred_iterator IP = SU->Preds.begin(), EP = SU->Preds.end(); - IP != EP; ++IP) { - if (IP->getKind() != SDep::Anti) - continue; - DepsAdded.push_back(std::make_pair(SU, *IP)); - } + for (SUnit &SU : SUnits) { + for (SDep &Pred : SU.Preds) + if (Pred.getKind() == SDep::Anti) + DepsAdded.push_back(std::make_pair(&SU, Pred)); } for (std::pair &P : DepsAdded) { // Remove this anti dependency and add one in the reverse direction. @@ -1471,27 +1465,23 @@ void SwingSchedulerDAG::computeNodeFunctions(NodeSetType &NodeSets) { } // Compute ALAP, ZeroLatencyHeight, and MOV. - for (ScheduleDAGTopologicalSort::const_reverse_iterator I = Topo.rbegin(), - E = Topo.rend(); - I != E; ++I) { + for (int I : llvm::reverse(Topo)) { int alap = maxASAP; int zeroLatencyHeight = 0; - SUnit *SU = &SUnits[*I]; - for (SUnit::const_succ_iterator IS = SU->Succs.begin(), - ES = SU->Succs.end(); - IS != ES; ++IS) { - SUnit *succ = IS->getSUnit(); - if (IS->getLatency() == 0) + SUnit *SU = &SUnits[I]; + for (const SDep &S : SU->Succs) { + SUnit *succ = S.getSUnit(); + if (S.getLatency() == 0) zeroLatencyHeight = std::max(zeroLatencyHeight, getZeroLatencyHeight(succ) + 1); - if (ignoreDependence(*IS, true)) + if (ignoreDependence(S, true)) continue; - alap = std::min(alap, (int)(getALAP(succ) - IS->getLatency() + - getDistance(SU, succ, *IS) * MII)); + alap = std::min(alap, (int)(getALAP(succ) - S.getLatency() + + getDistance(SU, succ, S) * MII)); } - ScheduleInfo[*I].ALAP = alap; - ScheduleInfo[*I].ZeroLatencyHeight = zeroLatencyHeight; + ScheduleInfo[I].ALAP = alap; + ScheduleInfo[I].ZeroLatencyHeight = zeroLatencyHeight; } // After computing the node functions, compute the summary for each node set. @@ -1548,9 +1538,8 @@ static bool succ_L(SetVector &NodeOrder, SmallSetVector &Succs, const NodeSet *S = nullptr) { Succs.clear(); - for (SetVector::iterator I = NodeOrder.begin(), E = NodeOrder.end(); - I != E; ++I) { - for (SDep &Succ : (*I)->Succs) { + for (const SUnit *SU : NodeOrder) { + for (const SDep &Succ : SU->Succs) { if (S && S->count(Succ.getSUnit()) == 0) continue; if (ignoreDependence(Succ, false)) @@ -1558,7 +1547,7 @@ static bool succ_L(SetVector &NodeOrder, if (NodeOrder.count(Succ.getSUnit()) == 0) Succs.insert(Succ.getSUnit()); } - for (SDep &Pred : (*I)->Preds) { + for (const SDep &Pred : SU->Preds) { if (Pred.getKind() != SDep::Anti) continue; if (S && S->count(Pred.getSUnit()) == 0) @@ -2202,7 +2191,7 @@ bool SwingSchedulerDAG::canUseLastOffsetValue(MachineInstr *MI, MachineInstr *NewMI = MF.CloneMachineInstr(MI); NewMI->getOperand(OffsetPosLd).setImm(LoadOffset + StoreOffset); bool Disjoint = TII->areMemAccessesTriviallyDisjoint(*NewMI, *PrevDef); - MF.DeleteMachineInstr(NewMI); + MF.deleteMachineInstr(NewMI); if (!Disjoint) return false; @@ -2885,10 +2874,8 @@ void SMSchedule::finalizeSchedule(SwingSchedulerDAG *SSD) { ++stage) { std::deque &cycleInstrs = ScheduledInstrs[cycle + (stage * InitiationInterval)]; - for (std::deque::reverse_iterator I = cycleInstrs.rbegin(), - E = cycleInstrs.rend(); - I != E; ++I) - ScheduledInstrs[cycle].push_front(*I); + for (SUnit *SU : llvm::reverse(cycleInstrs)) + ScheduledInstrs[cycle].push_front(SU); } } @@ -2899,10 +2886,8 @@ void SMSchedule::finalizeSchedule(SwingSchedulerDAG *SSD) { // Change the registers in instruction as specified in the InstrChanges // map. We need to use the new registers to create the correct order. - for (int i = 0, e = SSD->SUnits.size(); i != e; ++i) { - SUnit *SU = &SSD->SUnits[i]; - SSD->applyInstrChange(SU->getInstr(), *this); - } + for (const SUnit &SU : SSD->SUnits) + SSD->applyInstrChange(SU.getInstr(), *this); // Reorder the instructions in each cycle to fix and improve the // generated code. diff --git a/llvm/lib/CodeGen/MachineSSAContext.cpp b/llvm/lib/CodeGen/MachineSSAContext.cpp new file mode 100644 index 000000000000..8db893535daf --- /dev/null +++ b/llvm/lib/CodeGen/MachineSSAContext.cpp @@ -0,0 +1,52 @@ +//===- MachineSSAContext.cpp ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines a specialization of the GenericSSAContext +/// template class for Machine IR. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineSSAContext.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +MachineBasicBlock *MachineSSAContext::getEntryBlock(MachineFunction &F) { + return &F.front(); +} + +void MachineSSAContext::setFunction(MachineFunction &Fn) { + MF = &Fn; + RegInfo = &MF->getRegInfo(); +} + +Printable MachineSSAContext::print(MachineBasicBlock *Block) const { + return Printable([Block](raw_ostream &Out) { Block->printName(Out); }); +} + +Printable MachineSSAContext::print(MachineInstr *I) const { + return Printable([I](raw_ostream &Out) { I->print(Out); }); +} + +Printable MachineSSAContext::print(Register Value) const { + auto *MRI = RegInfo; + return Printable([MRI, Value](raw_ostream &Out) { + Out << printReg(Value, MRI->getTargetRegisterInfo(), 0, MRI); + + if (Value) { + // Try to print the definition. + if (auto *Instr = MRI->getUniqueVRegDef(Value)) { + Out << ": "; + Instr->print(Out); + } + } + }); +} diff --git a/llvm/lib/CodeGen/MachineSSAUpdater.cpp b/llvm/lib/CodeGen/MachineSSAUpdater.cpp index 930677e4fd7d..48076663ddf5 100644 --- a/llvm/lib/CodeGen/MachineSSAUpdater.cpp +++ b/llvm/lib/CodeGen/MachineSSAUpdater.cpp @@ -126,7 +126,9 @@ MachineInstrBuilder InsertNewDef(unsigned Opcode, } /// GetValueInMiddleOfBlock - Construct SSA form, materializing a value that -/// is live in the middle of the specified block. +/// is live in the middle of the specified block. If ExistingValueOnly is +/// true then this will only return an existing value or $noreg; otherwise new +/// instructions may be inserted to materialize a value. /// /// GetValueInMiddleOfBlock is the same as GetValueAtEndOfBlock except in one /// important case: if there is a definition of the rewritten value after the @@ -143,14 +145,18 @@ MachineInstrBuilder InsertNewDef(unsigned Opcode, /// their respective blocks. However, the use of X happens in the *middle* of /// a block. Because of this, we need to insert a new PHI node in SomeBB to /// merge the appropriate values, and this value isn't live out of the block. -Register MachineSSAUpdater::GetValueInMiddleOfBlock(MachineBasicBlock *BB) { +Register MachineSSAUpdater::GetValueInMiddleOfBlock(MachineBasicBlock *BB, + bool ExistingValueOnly) { // If there is no definition of the renamed variable in this block, just use // GetValueAtEndOfBlock to do our work. if (!HasValueForBlock(BB)) - return GetValueAtEndOfBlockInternal(BB); + return GetValueAtEndOfBlockInternal(BB, ExistingValueOnly); // If there are no predecessors, just return undef. if (BB->pred_empty()) { + // If we cannot insert new instructions, just return $noreg. + if (ExistingValueOnly) + return Register(); // Insert an implicit_def to represent an undef value. MachineInstr *NewDef = InsertNewDef(TargetOpcode::IMPLICIT_DEF, BB, BB->getFirstTerminator(), @@ -165,7 +171,7 @@ Register MachineSSAUpdater::GetValueInMiddleOfBlock(MachineBasicBlock *BB) { bool isFirstPred = true; for (MachineBasicBlock *PredBB : BB->predecessors()) { - Register PredVal = GetValueAtEndOfBlockInternal(PredBB); + Register PredVal = GetValueAtEndOfBlockInternal(PredBB, ExistingValueOnly); PredValues.push_back(std::make_pair(PredBB, PredVal)); // Compute SingularValue. @@ -185,6 +191,10 @@ Register MachineSSAUpdater::GetValueInMiddleOfBlock(MachineBasicBlock *BB) { if (DupPHI) return DupPHI; + // If we cannot create new instructions, return $noreg now. + if (ExistingValueOnly) + return Register(); + // Otherwise, we do need a PHI: insert one now. MachineBasicBlock::iterator Loc = BB->empty() ? BB->end() : BB->begin(); MachineInstrBuilder InsertedPHI = InsertNewDef(TargetOpcode::PHI, BB, @@ -350,10 +360,13 @@ public: /// for the specified BB and if so, return it. If not, construct SSA form by /// first calculating the required placement of PHIs and then inserting new /// PHIs where needed. -Register MachineSSAUpdater::GetValueAtEndOfBlockInternal(MachineBasicBlock *BB){ +Register +MachineSSAUpdater::GetValueAtEndOfBlockInternal(MachineBasicBlock *BB, + bool ExistingValueOnly) { AvailableValsTy &AvailableVals = getAvailableVals(AV); - if (Register V = AvailableVals[BB]) - return V; + Register ExistingVal = AvailableVals.lookup(BB); + if (ExistingVal || ExistingValueOnly) + return ExistingVal; SSAUpdaterImpl Impl(this, &AvailableVals, InsertedPHIs); return Impl.GetValue(BB); diff --git a/llvm/lib/CodeGen/MachineScheduler.cpp b/llvm/lib/CodeGen/MachineScheduler.cpp index 47d40f0823c8..b043d4c1b0c1 100644 --- a/llvm/lib/CodeGen/MachineScheduler.cpp +++ b/llvm/lib/CodeGen/MachineScheduler.cpp @@ -90,12 +90,17 @@ cl::opt VerifyScheduling( "verify-misched", cl::Hidden, cl::desc("Verify machine instrs before and after machine scheduling")); +#ifndef NDEBUG +cl::opt ViewMISchedDAGs( + "view-misched-dags", cl::Hidden, + cl::desc("Pop up a window to show MISched dags after they are processed")); +#else +const bool ViewMISchedDAGs = false; +#endif // NDEBUG + } // end namespace llvm #ifndef NDEBUG -static cl::opt ViewMISchedDAGs("view-misched-dags", cl::Hidden, - cl::desc("Pop up a window to show MISched dags after they are processed")); - /// In some situations a few uninteresting nodes depend on nearly all other /// nodes in the graph, provide a cutoff to hide them. static cl::opt ViewMISchedCutoff("view-misched-cutoff", cl::Hidden, @@ -111,7 +116,6 @@ static cl::opt SchedOnlyBlock("misched-only-block", cl::Hidden, static cl::opt PrintDAGs("misched-print-dags", cl::Hidden, cl::desc("Print schedule DAGs")); #else -static const bool ViewMISchedDAGs = false; static const bool PrintDAGs = false; #endif // NDEBUG @@ -561,11 +565,10 @@ void MachineSchedulerBase::scheduleRegions(ScheduleDAGInstrs &Scheduler, MBBRegionsVector MBBRegions; getSchedRegions(&*MBB, MBBRegions, Scheduler.doMBBSchedRegionsTopDown()); - for (MBBRegionsVector::iterator R = MBBRegions.begin(); - R != MBBRegions.end(); ++R) { - MachineBasicBlock::iterator I = R->RegionBegin; - MachineBasicBlock::iterator RegionEnd = R->RegionEnd; - unsigned NumRegionInstrs = R->NumRegionInstrs; + for (const SchedRegion &R : MBBRegions) { + MachineBasicBlock::iterator I = R.RegionBegin; + MachineBasicBlock::iterator RegionEnd = R.RegionEnd; + unsigned NumRegionInstrs = R.NumRegionInstrs; // Notify the scheduler of the region, even if we may skip scheduling // it. Perhaps it still needs to be bundled. diff --git a/llvm/lib/CodeGen/MachineTraceMetrics.cpp b/llvm/lib/CodeGen/MachineTraceMetrics.cpp index 8df23b781ffd..0a5ff276fedc 100644 --- a/llvm/lib/CodeGen/MachineTraceMetrics.cpp +++ b/llvm/lib/CodeGen/MachineTraceMetrics.cpp @@ -80,9 +80,9 @@ bool MachineTraceMetrics::runOnMachineFunction(MachineFunction &Func) { void MachineTraceMetrics::releaseMemory() { MF = nullptr; BlockInfo.clear(); - for (unsigned i = 0; i != TS_NumStrategies; ++i) { - delete Ensembles[i]; - Ensembles[i] = nullptr; + for (Ensemble *&E : Ensembles) { + delete E; + E = nullptr; } } @@ -398,9 +398,9 @@ void MachineTraceMetrics::invalidate(const MachineBasicBlock *MBB) { LLVM_DEBUG(dbgs() << "Invalidate traces through " << printMBBReference(*MBB) << '\n'); BlockInfo[MBB->getNumber()].invalidate(); - for (unsigned i = 0; i != TS_NumStrategies; ++i) - if (Ensembles[i]) - Ensembles[i]->invalidate(MBB); + for (Ensemble *E : Ensembles) + if (E) + E->invalidate(MBB); } void MachineTraceMetrics::verifyAnalysis() const { @@ -408,9 +408,9 @@ void MachineTraceMetrics::verifyAnalysis() const { return; #ifndef NDEBUG assert(BlockInfo.size() == MF->getNumBlockIDs() && "Outdated BlockInfo size"); - for (unsigned i = 0; i != TS_NumStrategies; ++i) - if (Ensembles[i]) - Ensembles[i]->verify(); + for (Ensemble *E : Ensembles) + if (E) + E->verify(); #endif } @@ -984,8 +984,7 @@ addLiveIns(const MachineInstr *DefMI, unsigned DefOp, const MachineBasicBlock *DefMBB = DefMI->getParent(); // Reg is live-in to all blocks in Trace that follow DefMBB. - for (unsigned i = Trace.size(); i; --i) { - const MachineBasicBlock *MBB = Trace[i-1]; + for (const MachineBasicBlock *MBB : llvm::reverse(Trace)) { if (MBB == DefMBB) return; TraceBlockInfo &TBI = BlockInfo[MBB->getNumber()]; @@ -1204,8 +1203,8 @@ unsigned MachineTraceMetrics::Trace::getResourceDepth(bool Bottom) const { for (unsigned K = 0; K != PRDepths.size(); ++K) PRMax = std::max(PRMax, PRDepths[K] + PRCycles[K]); } else { - for (unsigned K = 0; K != PRDepths.size(); ++K) - PRMax = std::max(PRMax, PRDepths[K]); + for (unsigned PRD : PRDepths) + PRMax = std::max(PRMax, PRD); } // Convert to cycle count. PRMax = TE.MTM.getCycles(PRMax); diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp index 32078db76cf3..005d4ad1a328 100644 --- a/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/llvm/lib/CodeGen/MachineVerifier.cpp @@ -101,6 +101,7 @@ namespace { // Avoid querying the MachineFunctionProperties for each operand. bool isFunctionRegBankSelected; bool isFunctionSelected; + bool isFunctionTracksDebugUserValues; using RegVector = SmallVector; using RegMaskVector = SmallVector; @@ -384,6 +385,8 @@ unsigned MachineVerifier::verify(const MachineFunction &MF) { MachineFunctionProperties::Property::RegBankSelected); isFunctionSelected = MF.getProperties().hasProperty( MachineFunctionProperties::Property::Selected); + isFunctionTracksDebugUserValues = MF.getProperties().hasProperty( + MachineFunctionProperties::Property::TracksDebugUserValues); LiveVars = nullptr; LiveInts = nullptr; @@ -1605,12 +1608,16 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) { } break; } + case TargetOpcode::G_SHL: + case TargetOpcode::G_LSHR: + case TargetOpcode::G_ASHR: case TargetOpcode::G_ROTR: case TargetOpcode::G_ROTL: { LLT Src1Ty = MRI->getType(MI->getOperand(1).getReg()); LLT Src2Ty = MRI->getType(MI->getOperand(2).getReg()); if (Src1Ty.isVector() != Src2Ty.isVector()) { - report("Rotate requires operands to be either all scalars or all vectors", + report("Shifts and rotates require operands to be either all scalars or " + "all vectors", MI); break; } @@ -1980,41 +1987,50 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { if (MO->isUndef()) report("Generic virtual register use cannot be undef", MO, MONum); - // If we're post-Select, we can't have gvregs anymore. - if (isFunctionSelected) { - report("Generic virtual register invalid in a Selected function", - MO, MONum); - return; - } + // Debug value instruction is permitted to use undefined vregs. + // This is a performance measure to skip the overhead of immediately + // pruning unused debug operands. The final undef substitution occurs + // when debug values are allocated in LDVImpl::handleDebugValue, so + // these verifications always apply after this pass. + if (isFunctionTracksDebugUserValues || !MO->isUse() || + !MI->isDebugValue() || !MRI->def_empty(Reg)) { + // If we're post-Select, we can't have gvregs anymore. + if (isFunctionSelected) { + report("Generic virtual register invalid in a Selected function", + MO, MONum); + return; + } - // The gvreg must have a type and it must not have a SubIdx. - LLT Ty = MRI->getType(Reg); - if (!Ty.isValid()) { - report("Generic virtual register must have a valid type", MO, - MONum); - return; - } + // The gvreg must have a type and it must not have a SubIdx. + LLT Ty = MRI->getType(Reg); + if (!Ty.isValid()) { + report("Generic virtual register must have a valid type", MO, + MONum); + return; + } - const RegisterBank *RegBank = MRI->getRegBankOrNull(Reg); + const RegisterBank *RegBank = MRI->getRegBankOrNull(Reg); - // If we're post-RegBankSelect, the gvreg must have a bank. - if (!RegBank && isFunctionRegBankSelected) { - report("Generic virtual register must have a bank in a " - "RegBankSelected function", - MO, MONum); - return; - } + // If we're post-RegBankSelect, the gvreg must have a bank. + if (!RegBank && isFunctionRegBankSelected) { + report("Generic virtual register must have a bank in a " + "RegBankSelected function", + MO, MONum); + return; + } - // Make sure the register fits into its register bank if any. - if (RegBank && Ty.isValid() && - RegBank->getSize() < Ty.getSizeInBits()) { - report("Register bank is too small for virtual register", MO, - MONum); - errs() << "Register bank " << RegBank->getName() << " too small(" - << RegBank->getSize() << ") to fit " << Ty.getSizeInBits() - << "-bits\n"; - return; + // Make sure the register fits into its register bank if any. + if (RegBank && Ty.isValid() && + RegBank->getSize() < Ty.getSizeInBits()) { + report("Register bank is too small for virtual register", MO, + MONum); + errs() << "Register bank " << RegBank->getName() << " too small(" + << RegBank->getSize() << ") to fit " << Ty.getSizeInBits() + << "-bits\n"; + return; + } } + if (SubIdx) { report("Generic virtual register does not allow subregister index", MO, MONum); @@ -2217,8 +2233,8 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) { if (LiveInts && Reg.isVirtual()) { if (LiveInts->hasInterval(Reg)) { LI = &LiveInts->getInterval(Reg); - if (SubRegIdx != 0 && !LI->empty() && !LI->hasSubRanges() && - MRI->shouldTrackSubRegLiveness(Reg)) + if (SubRegIdx != 0 && (MO->isDef() || !MO->isUndef()) && !LI->empty() && + !LI->hasSubRanges() && MRI->shouldTrackSubRegLiveness(Reg)) report("Live interval for subreg operand has no subranges", MO, MONum); } else { report("Virtual register has no live interval", MO, MONum); diff --git a/llvm/lib/CodeGen/PHIElimination.cpp b/llvm/lib/CodeGen/PHIElimination.cpp index 77a6c37e1362..7693ab417de9 100644 --- a/llvm/lib/CodeGen/PHIElimination.cpp +++ b/llvm/lib/CodeGen/PHIElimination.cpp @@ -213,7 +213,7 @@ bool PHIElimination::runOnMachineFunction(MachineFunction &MF) { for (auto &I : LoweredPHIs) { if (LIS) LIS->RemoveMachineInstrFromMaps(*I.first); - MF.DeleteMachineInstr(I.first); + MF.deleteMachineInstr(I.first); } // TODO: we should use the incremental DomTree updater here. @@ -626,7 +626,7 @@ void PHIElimination::LowerPHINode(MachineBasicBlock &MBB, if (reusedIncoming || !IncomingReg) { if (LIS) LIS->RemoveMachineInstrFromMaps(*MPhi); - MF.DeleteMachineInstr(MPhi); + MF.deleteMachineInstr(MPhi); } } diff --git a/llvm/lib/CodeGen/PostRASchedulerList.cpp b/llvm/lib/CodeGen/PostRASchedulerList.cpp index b85f00a61eac..d7cd0a583cee 100644 --- a/llvm/lib/CodeGen/PostRASchedulerList.cpp +++ b/llvm/lib/CodeGen/PostRASchedulerList.cpp @@ -252,8 +252,8 @@ void SchedulePostRATDList::exitRegion() { #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) /// dumpSchedule - dump the scheduled Sequence. LLVM_DUMP_METHOD void SchedulePostRATDList::dumpSchedule() const { - for (unsigned i = 0, e = Sequence.size(); i != e; i++) { - if (SUnit *SU = Sequence[i]) + for (const SUnit *SU : Sequence) { + if (SU) dumpNode(*SU); else dbgs() << "**** NOOP ****\n"; @@ -531,11 +531,11 @@ void SchedulePostRATDList::ListScheduleTopDown() { ReleaseSuccessors(&EntrySU); // Add all leaves to Available queue. - for (unsigned i = 0, e = SUnits.size(); i != e; ++i) { + for (SUnit &SUnit : SUnits) { // It is available if it has no predecessors. - if (!SUnits[i].NumPredsLeft && !SUnits[i].isAvailable) { - AvailableQueue.push(&SUnits[i]); - SUnits[i].isAvailable = true; + if (!SUnit.NumPredsLeft && !SUnit.isAvailable) { + AvailableQueue.push(&SUnit); + SUnit.isAvailable = true; } } @@ -657,10 +657,7 @@ void SchedulePostRATDList::ListScheduleTopDown() { #ifndef NDEBUG unsigned ScheduledNodes = VerifyScheduledDAG(/*isBottomUp=*/false); - unsigned Noops = 0; - for (unsigned i = 0, e = Sequence.size(); i != e; ++i) - if (!Sequence[i]) - ++Noops; + unsigned Noops = llvm::count(Sequence, nullptr); assert(Sequence.size() - Noops == ScheduledNodes && "The number of nodes scheduled doesn't match the expected number!"); #endif // NDEBUG diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp index 29a88480fd9f..8d8a6126dad0 100644 --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -953,12 +953,22 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &MF) { // LocalStackSlotPass didn't already allocate a slot for it. // If we are told to use the LocalStackAllocationBlock, the stack protector // is expected to be already pre-allocated. - if (!MFI.getUseLocalStackAllocationBlock()) + if (MFI.getStackID(StackProtectorFI) != TargetStackID::Default) { + // If the stack protector isn't on the default stack then it's up to the + // target to set the stack offset. + assert(MFI.getObjectOffset(StackProtectorFI) != 0 && + "Offset of stack protector on non-default stack expected to be " + "already set."); + assert(!MFI.isObjectPreAllocated(MFI.getStackProtectorIndex()) && + "Stack protector on non-default stack expected to not be " + "pre-allocated by LocalStackSlotPass."); + } else if (!MFI.getUseLocalStackAllocationBlock()) { AdjustStackOffset(MFI, StackProtectorFI, StackGrowsDown, Offset, MaxAlign, Skew); - else if (!MFI.isObjectPreAllocated(MFI.getStackProtectorIndex())) + } else if (!MFI.isObjectPreAllocated(MFI.getStackProtectorIndex())) { llvm_unreachable( "Stack protector not pre-allocated by LocalStackSlotPass."); + } // Assign large stack objects first. for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) { diff --git a/llvm/lib/CodeGen/RDFGraph.cpp b/llvm/lib/CodeGen/RDFGraph.cpp index f605068e076d..882f8e91bf1d 100644 --- a/llvm/lib/CodeGen/RDFGraph.cpp +++ b/llvm/lib/CodeGen/RDFGraph.cpp @@ -1500,8 +1500,8 @@ void DataFlowGraph::buildPhis(BlockRefsMap &PhiM, RegisterSet &AllRefs, // Erase from MaxRefs all elements in the closure. auto Begin = MaxRefs.begin(); - for (unsigned i = ClosureIdx.size(); i != 0; --i) - MaxRefs.erase(Begin + ClosureIdx[i-1]); + for (unsigned Idx : llvm::reverse(ClosureIdx)) + MaxRefs.erase(Begin + Idx); } } diff --git a/llvm/lib/CodeGen/RegAllocEvictionAdvisor.cpp b/llvm/lib/CodeGen/RegAllocEvictionAdvisor.cpp new file mode 100644 index 000000000000..9f1012c95964 --- /dev/null +++ b/llvm/lib/CodeGen/RegAllocEvictionAdvisor.cpp @@ -0,0 +1,121 @@ +//===- RegAllocEvictionAdvisor.cpp - eviction advisor ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of the default eviction advisor and of the Analysis pass. +// +//===----------------------------------------------------------------------===// + +#include "RegAllocEvictionAdvisor.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/RegisterClassInfo.h" +#include "llvm/CodeGen/VirtRegMap.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +static cl::opt Mode( + "regalloc-enable-advisor", cl::Hidden, + cl::init(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Default), + cl::desc("Enable regalloc advisor mode"), + cl::values( + clEnumValN(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Default, + "default", "Default"), + clEnumValN(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Release, + "release", "precompiled"), + clEnumValN(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Development, + "development", "for training"))); + +static cl::opt EnableLocalReassignment( + "enable-local-reassign", cl::Hidden, + cl::desc("Local reassignment can yield better allocation decisions, but " + "may be compile time intensive"), + cl::init(false)); + +#define DEBUG_TYPE "regalloc" + +char RegAllocEvictionAdvisorAnalysis::ID = 0; +INITIALIZE_PASS(RegAllocEvictionAdvisorAnalysis, "regalloc-evict", + "Regalloc eviction policy", false, true) + +namespace { +class DefaultEvictionAdvisorAnalysis final + : public RegAllocEvictionAdvisorAnalysis { +public: + DefaultEvictionAdvisorAnalysis(bool NotAsRequested) + : RegAllocEvictionAdvisorAnalysis(AdvisorMode::Default), + NotAsRequested(NotAsRequested) {} + + // support for isa<> and dyn_cast. + static bool classof(const RegAllocEvictionAdvisorAnalysis *R) { + return R->getAdvisorMode() == AdvisorMode::Default; + } + +private: + std::unique_ptr + getAdvisor(const MachineFunction &MF, LiveRegMatrix *Matrix, + LiveIntervals *LIS, VirtRegMap *VRM, + const RegisterClassInfo &RegClassInfo, + ExtraRegInfo *ExtraInfo) override { + return std::make_unique(MF, Matrix, LIS, VRM, + RegClassInfo, ExtraInfo); + } + bool doInitialization(Module &M) override { + if (NotAsRequested) + M.getContext().emitError("Requested regalloc eviction advisor analysis " + "could be created. Using default"); + return RegAllocEvictionAdvisorAnalysis::doInitialization(M); + } + const bool NotAsRequested; +}; +} // namespace + +template <> Pass *llvm::callDefaultCtor() { + Pass *Ret = nullptr; + switch (Mode) { + case RegAllocEvictionAdvisorAnalysis::AdvisorMode::Default: + Ret = new DefaultEvictionAdvisorAnalysis(/*NotAsRequested*/ false); + break; + case RegAllocEvictionAdvisorAnalysis::AdvisorMode::Development: + // TODO(mtrofin): add implementation + break; + case RegAllocEvictionAdvisorAnalysis::AdvisorMode::Release: + // TODO(mtrofin): add implementation + break; + } + if (Ret) + return Ret; + return new DefaultEvictionAdvisorAnalysis(/*NotAsRequested*/ true); +} + +StringRef RegAllocEvictionAdvisorAnalysis::getPassName() const { + switch (getAdvisorMode()) { + case AdvisorMode::Default: + return "Default Regalloc Eviction Advisor"; + case AdvisorMode::Release: + return "Release mode Regalloc Eviction Advisor"; + case AdvisorMode::Development: + return "Development mode Regalloc Eviction Advisor"; + } + llvm_unreachable("Unknown advisor kind"); +} + +RegAllocEvictionAdvisor::RegAllocEvictionAdvisor( + const MachineFunction &MF, LiveRegMatrix *Matrix, LiveIntervals *LIS, + VirtRegMap *VRM, const RegisterClassInfo &RegClassInfo, + ExtraRegInfo *ExtraInfo) + : MF(MF), Matrix(Matrix), LIS(LIS), VRM(VRM), MRI(&VRM->getRegInfo()), + TRI(MF.getSubtarget().getRegisterInfo()), RegClassInfo(RegClassInfo), + RegCosts(TRI->getRegisterCosts(MF)), ExtraInfo(ExtraInfo), + EnableLocalReassign(EnableLocalReassignment || + MF.getSubtarget().enableRALocalReassignment( + MF.getTarget().getOptLevel())) {} diff --git a/llvm/lib/CodeGen/RegAllocEvictionAdvisor.h b/llvm/lib/CodeGen/RegAllocEvictionAdvisor.h index 85fd3207888b..debb75ed5020 100644 --- a/llvm/lib/CodeGen/RegAllocEvictionAdvisor.h +++ b/llvm/lib/CodeGen/RegAllocEvictionAdvisor.h @@ -18,6 +18,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Register.h" #include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Pass.h" namespace llvm { @@ -85,6 +86,215 @@ struct EvictionCost { std::tie(O.BrokenHints, O.MaxWeight); } }; + +/// Track allocation stage and eviction loop prevention during allocation. +// TODO(mtrofin): Consider exposing RAGreedy in a header instead, and folding +// this back into it. +class ExtraRegInfo final { + // RegInfo - Keep additional information about each live range. + struct RegInfo { + LiveRangeStage Stage = RS_New; + + // Cascade - Eviction loop prevention. See + // canEvictInterferenceBasedOnCost(). + unsigned Cascade = 0; + + RegInfo() = default; + }; + + IndexedMap Info; + unsigned NextCascade = 1; + +public: + ExtraRegInfo() = default; + ExtraRegInfo(const ExtraRegInfo &) = delete; + + LiveRangeStage getStage(Register Reg) const { return Info[Reg].Stage; } + + LiveRangeStage getStage(const LiveInterval &VirtReg) const { + return getStage(VirtReg.reg()); + } + + void setStage(Register Reg, LiveRangeStage Stage) { + Info.grow(Reg.id()); + Info[Reg].Stage = Stage; + } + + void setStage(const LiveInterval &VirtReg, LiveRangeStage Stage) { + setStage(VirtReg.reg(), Stage); + } + + /// Return the current stage of the register, if present, otherwise initialize + /// it and return that. + LiveRangeStage getOrInitStage(Register Reg) { + Info.grow(Reg.id()); + return getStage(Reg); + } + + unsigned getCascade(Register Reg) const { return Info[Reg].Cascade; } + + void setCascade(Register Reg, unsigned Cascade) { + Info.grow(Reg.id()); + Info[Reg].Cascade = Cascade; + } + + unsigned getOrAssignNewCascade(Register Reg) { + unsigned Cascade = getCascade(Reg); + if (!Cascade) { + Cascade = NextCascade++; + setCascade(Reg, Cascade); + } + return Cascade; + } + + unsigned getCascadeOrCurrentNext(Register Reg) const { + unsigned Cascade = getCascade(Reg); + if (!Cascade) + Cascade = NextCascade; + return Cascade; + } + + template + void setStage(Iterator Begin, Iterator End, LiveRangeStage NewStage) { + for (; Begin != End; ++Begin) { + Register Reg = *Begin; + Info.grow(Reg.id()); + if (Info[Reg].Stage == RS_New) + Info[Reg].Stage = NewStage; + } + } + void LRE_DidCloneVirtReg(Register New, Register Old); +}; + +/// Interface to the eviction advisor, which is responsible for making a +/// decision as to which live ranges should be evicted (if any). +class RegAllocEvictionAdvisor { +public: + RegAllocEvictionAdvisor(const RegAllocEvictionAdvisor &) = delete; + RegAllocEvictionAdvisor(RegAllocEvictionAdvisor &&) = delete; + virtual ~RegAllocEvictionAdvisor() = default; + + /// Find a physical register that can be freed by evicting the FixedRegisters, + /// or return NoRegister. The eviction decision is assumed to be correct (i.e. + /// no fixed live ranges are evicted) and profitable. + virtual MCRegister + tryFindEvictionCandidate(LiveInterval &VirtReg, const AllocationOrder &Order, + uint8_t CostPerUseLimit, + const SmallVirtRegSet &FixedRegisters) const = 0; + + /// Find out if we can evict the live ranges occupying the given PhysReg, + /// which is a hint (preferred register) for VirtReg. + virtual bool + canEvictHintInterference(LiveInterval &VirtReg, MCRegister PhysReg, + const SmallVirtRegSet &FixedRegisters) const = 0; + + /// Returns true if the given \p PhysReg is a callee saved register and has + /// not been used for allocation yet. + bool isUnusedCalleeSavedReg(MCRegister PhysReg) const; + +protected: + RegAllocEvictionAdvisor(const MachineFunction &MF, LiveRegMatrix *Matrix, + LiveIntervals *LIS, VirtRegMap *VRM, + const RegisterClassInfo &RegClassInfo, + ExtraRegInfo *ExtraInfo); + + Register canReassign(LiveInterval &VirtReg, Register PrevReg) const; + + const MachineFunction &MF; + LiveRegMatrix *const Matrix; + LiveIntervals *const LIS; + VirtRegMap *const VRM; + MachineRegisterInfo *const MRI; + const TargetRegisterInfo *const TRI; + const RegisterClassInfo &RegClassInfo; + const ArrayRef RegCosts; + ExtraRegInfo *const ExtraInfo; + + /// Run or not the local reassignment heuristic. This information is + /// obtained from the TargetSubtargetInfo. + const bool EnableLocalReassign; + +private: + unsigned NextCascade = 1; +}; + +/// ImmutableAnalysis abstraction for fetching the Eviction Advisor. We model it +/// as an analysis to decouple the user from the implementation insofar as +/// dependencies on other analyses goes. The motivation for it being an +/// immutable pass is twofold: +/// - in the ML implementation case, the evaluator is stateless but (especially +/// in the development mode) expensive to set up. With an immutable pass, we set +/// it up once. +/// - in the 'development' mode ML case, we want to capture the training log +/// during allocation (this is a log of features encountered and decisions +/// made), and then measure a score, potentially a few steps after allocation +/// completes. So we need the properties of an immutable pass to keep the logger +/// state around until we can make that measurement. +/// +/// Because we need to offer additional services in 'development' mode, the +/// implementations of this analysis need to implement RTTI support. +class RegAllocEvictionAdvisorAnalysis : public ImmutablePass { +public: + enum class AdvisorMode : int { Default, Release, Development }; + + RegAllocEvictionAdvisorAnalysis(AdvisorMode Mode) + : ImmutablePass(ID), Mode(Mode){}; + static char ID; + + /// Get an advisor for the given context (i.e. machine function, etc) + virtual std::unique_ptr + getAdvisor(const MachineFunction &MF, LiveRegMatrix *Matrix, + LiveIntervals *LIS, VirtRegMap *VRM, + const RegisterClassInfo &RegClassInfo, + ExtraRegInfo *ExtraInfo) = 0; + AdvisorMode getAdvisorMode() const { return Mode; } + +private: + // This analysis preserves everything, and subclasses may have additional + // requirements. + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + StringRef getPassName() const override; + const AdvisorMode Mode; +}; + +/// Specialization for the API used by the analysis infrastructure to create +/// an instance of the eviction advisor. +template <> Pass *callDefaultCtor(); + +// TODO(mtrofin): implement these. +#ifdef LLVM_HAVE_TF_AOT +RegAllocEvictionAdvisorAnalysis *createReleaseModeAdvisor(); +#endif + +#ifdef LLVM_HAVE_TF_API +RegAllocEvictionAdvisorAnalysis *createDevelopmentModeAdvisor(); +#endif + +// TODO: move to RegAllocEvictionAdvisor.cpp when we move implementation +// out of RegAllocGreedy.cpp +class DefaultEvictionAdvisor : public RegAllocEvictionAdvisor { +public: + DefaultEvictionAdvisor(const MachineFunction &MF, LiveRegMatrix *Matrix, + LiveIntervals *LIS, VirtRegMap *VRM, + const RegisterClassInfo &RegClassInfo, + ExtraRegInfo *ExtraInfo) + : RegAllocEvictionAdvisor(MF, Matrix, LIS, VRM, RegClassInfo, ExtraInfo) { + } + +private: + MCRegister tryFindEvictionCandidate(LiveInterval &, const AllocationOrder &, + uint8_t, + const SmallVirtRegSet &) const override; + bool canEvictHintInterference(LiveInterval &, MCRegister, + const SmallVirtRegSet &) const override; + bool canEvictInterferenceBasedOnCost(LiveInterval &, MCRegister, bool, + EvictionCost &, + const SmallVirtRegSet &) const; + bool shouldEvict(LiveInterval &A, bool, LiveInterval &B, bool) const; +}; } // namespace llvm #endif // LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H diff --git a/llvm/lib/CodeGen/RegAllocGreedy.cpp b/llvm/lib/CodeGen/RegAllocGreedy.cpp index 50411c177007..ce3cf31dbd6b 100644 --- a/llvm/lib/CodeGen/RegAllocGreedy.cpp +++ b/llvm/lib/CodeGen/RegAllocGreedy.cpp @@ -112,12 +112,6 @@ static cl::opt ExhaustiveSearch( "and interference cutoffs of last chance recoloring"), cl::Hidden); -static cl::opt EnableLocalReassignment( - "enable-local-reassign", cl::Hidden, - cl::desc("Local reassignment can yield better allocation decisions, but " - "may be compile time intensive"), - cl::init(false)); - static cl::opt EnableDeferredSpilling( "enable-deferred-spilling", cl::Hidden, cl::desc("Instead of spilling a variable right away, defer the actual " @@ -172,8 +166,9 @@ class RAGreedy : public MachineFunctionPass, // state std::unique_ptr SpillerInstance; PQueue Queue; - unsigned NextCascade; std::unique_ptr VRAI; + Optional ExtraInfo; + std::unique_ptr EvictAdvisor; // Enum CutOffStage to keep a track whether the register allocation failed // because of the cutoffs encountered in last chance recoloring. @@ -195,76 +190,6 @@ class RAGreedy : public MachineFunctionPass, static const char *const StageName[]; #endif - // RegInfo - Keep additional information about each live range. - struct RegInfo { - LiveRangeStage Stage = RS_New; - - // Cascade - Eviction loop prevention. See - // canEvictInterferenceBasedOnCost(). - unsigned Cascade = 0; - - RegInfo() = default; - }; - - IndexedMap ExtraRegInfo; - - LiveRangeStage getStage(Register Reg) const { - return ExtraRegInfo[Reg].Stage; - } - - LiveRangeStage getStage(const LiveInterval &VirtReg) const { - return getStage(VirtReg.reg()); - } - - void setStage(Register Reg, LiveRangeStage Stage) { - ExtraRegInfo.resize(MRI->getNumVirtRegs()); - ExtraRegInfo[Reg].Stage = Stage; - } - - void setStage(const LiveInterval &VirtReg, LiveRangeStage Stage) { - setStage(VirtReg.reg(), Stage); - } - - /// Return the current stage of the register, if present, otherwise initialize - /// it and return that. - LiveRangeStage getOrInitStage(Register Reg) { - ExtraRegInfo.grow(Reg); - return getStage(Reg); - } - - unsigned getCascade(Register Reg) const { return ExtraRegInfo[Reg].Cascade; } - - void setCascade(Register Reg, unsigned Cascade) { - ExtraRegInfo.resize(MRI->getNumVirtRegs()); - ExtraRegInfo[Reg].Cascade = Cascade; - } - - unsigned getOrAssignNewCascade(Register Reg) { - unsigned Cascade = getCascade(Reg); - if (!Cascade) { - Cascade = NextCascade++; - setCascade(Reg, Cascade); - } - return Cascade; - } - - unsigned getCascadeOrCurrentNext(Register Reg) const { - unsigned Cascade = getCascade(Reg); - if (!Cascade) - Cascade = NextCascade; - return Cascade; - } - - template - void setStage(Iterator Begin, Iterator End, LiveRangeStage NewStage) { - ExtraRegInfo.resize(MRI->getNumVirtRegs()); - for (;Begin != End; ++Begin) { - Register Reg = *Begin; - if (ExtraRegInfo[Reg].Stage == RS_New) - ExtraRegInfo[Reg].Stage = NewStage; - } - } - /// EvictionTrack - Keeps track of past evictions in order to optimize region /// split decision. class EvictionTrack { @@ -375,10 +300,6 @@ class RAGreedy : public MachineFunctionPass, /// Callee-save register cost, calculated once per machine function. BlockFrequency CSRCost; - /// Run or not the local reassignment heuristic. This information is - /// obtained from the TargetSubtargetInfo. - bool EnableLocalReassign; - /// Enable or not the consideration of the cost of local intervals created /// by a split candidate when choosing the best split candidate. bool EnableAdvancedRASplitCost; @@ -447,13 +368,6 @@ private: bool calcCompactRegion(GlobalSplitCandidate&); void splitAroundRegion(LiveRangeEdit&, ArrayRef); void calcGapWeights(MCRegister, SmallVectorImpl &); - Register canReassign(LiveInterval &VirtReg, Register PrevReg) const; - bool shouldEvict(LiveInterval &A, bool, LiveInterval &B, bool) const; - bool canEvictInterferenceBasedOnCost(LiveInterval &, MCRegister, bool, - EvictionCost &, - const SmallVirtRegSet &) const; - bool canEvictHintInterference(LiveInterval &, MCRegister, - const SmallVirtRegSet &) const; bool canEvictInterferenceInRange(const LiveInterval &VirtReg, MCRegister PhysReg, SlotIndex Start, SlotIndex End, EvictionCost &MaxCost) const; @@ -529,8 +443,6 @@ private: BlockFrequency getBrokenHintFreq(const HintsInfo &, MCRegister); void collectHintInfo(Register, HintsInfo &); - bool isUnusedCalleeSavedReg(MCRegister PhysReg) const; - /// Greedy RA statistic to remark. struct RAGreedyStats { unsigned Reloads = 0; @@ -597,6 +509,7 @@ INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix) INITIALIZE_PASS_DEPENDENCY(EdgeBundles) INITIALIZE_PASS_DEPENDENCY(SpillPlacement) INITIALIZE_PASS_DEPENDENCY(MachineOptimizationRemarkEmitterPass) +INITIALIZE_PASS_DEPENDENCY(RegAllocEvictionAdvisorAnalysis) INITIALIZE_PASS_END(RAGreedy, "greedy", "Greedy Register Allocator", false, false) @@ -663,6 +576,7 @@ void RAGreedy::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -696,22 +610,25 @@ void RAGreedy::LRE_WillShrinkVirtReg(Register VirtReg) { } void RAGreedy::LRE_DidCloneVirtReg(Register New, Register Old) { + ExtraInfo->LRE_DidCloneVirtReg(New, Old); +} + +void ExtraRegInfo::LRE_DidCloneVirtReg(Register New, Register Old) { // Cloning a register we haven't even heard about yet? Just ignore it. - if (!ExtraRegInfo.inBounds(Old)) + if (!Info.inBounds(Old)) return; // LRE may clone a virtual register because dead code elimination causes it to // be split into connected components. The new components are much smaller // than the original, so they should get a new chance at being assigned. // same stage as the parent. - ExtraRegInfo[Old].Stage = RS_Assign; - ExtraRegInfo.grow(New); - ExtraRegInfo[New] = ExtraRegInfo[Old]; + Info[Old].Stage = RS_Assign; + Info.grow(New.id()); + Info[New] = Info[Old]; } void RAGreedy::releaseMemory() { SpillerInstance.reset(); - ExtraRegInfo.clear(); GlobalCand.clear(); } @@ -725,10 +642,10 @@ void RAGreedy::enqueue(PQueue &CurQueue, LiveInterval *LI) { assert(Reg.isVirtual() && "Can only enqueue virtual registers"); unsigned Prio; - auto Stage = getOrInitStage(Reg); + auto Stage = ExtraInfo->getOrInitStage(Reg); if (Stage == RS_New) { Stage = RS_Assign; - setStage(Reg, Stage); + ExtraInfo->setStage(Reg, Stage); } if (Stage == RS_Split) { // Unsplit ranges that couldn't be allocated immediately are deferred until @@ -824,7 +741,8 @@ MCRegister RAGreedy::tryAssign(LiveInterval &VirtReg, MCRegister PhysHint = Hint.asMCReg(); LLVM_DEBUG(dbgs() << "missed hint " << printReg(PhysHint, TRI) << '\n'); - if (canEvictHintInterference(VirtReg, PhysHint, FixedRegisters)) { + if (EvictAdvisor->canEvictHintInterference(VirtReg, PhysHint, + FixedRegisters)) { evictInterference(VirtReg, PhysHint, NewVRegs); return PhysHint; } @@ -850,7 +768,8 @@ MCRegister RAGreedy::tryAssign(LiveInterval &VirtReg, // Interference eviction //===----------------------------------------------------------------------===// -Register RAGreedy::canReassign(LiveInterval &VirtReg, Register PrevReg) const { +Register RegAllocEvictionAdvisor::canReassign(LiveInterval &VirtReg, + Register PrevReg) const { auto Order = AllocationOrder::create(VirtReg.reg(), *VRM, RegClassInfo, Matrix); MCRegister PhysReg; @@ -889,9 +808,10 @@ Register RAGreedy::canReassign(LiveInterval &VirtReg, Register PrevReg) const { /// register. /// @param B The live range to be evicted. /// @param BreaksHint True when B is already assigned to its preferred register. -bool RAGreedy::shouldEvict(LiveInterval &A, bool IsHint, - LiveInterval &B, bool BreaksHint) const { - bool CanSplit = getStage(B) < RS_Spill; +bool DefaultEvictionAdvisor::shouldEvict(LiveInterval &A, bool IsHint, + LiveInterval &B, + bool BreaksHint) const { + bool CanSplit = ExtraInfo->getStage(B) < RS_Spill; // Be fairly aggressive about following hints as long as the evictee can be // split. @@ -907,7 +827,7 @@ bool RAGreedy::shouldEvict(LiveInterval &A, bool IsHint, /// canEvictHintInterference - return true if the interference for VirtReg /// on the PhysReg, which is VirtReg's hint, can be evicted in favor of VirtReg. -bool RAGreedy::canEvictHintInterference( +bool DefaultEvictionAdvisor::canEvictHintInterference( LiveInterval &VirtReg, MCRegister PhysReg, const SmallVirtRegSet &FixedRegisters) const { EvictionCost MaxCost; @@ -925,7 +845,7 @@ bool RAGreedy::canEvictHintInterference( /// @param MaxCost Only look for cheaper candidates and update with new cost /// when returning true. /// @returns True when interference can be evicted cheaper than MaxCost. -bool RAGreedy::canEvictInterferenceBasedOnCost( +bool DefaultEvictionAdvisor::canEvictInterferenceBasedOnCost( LiveInterval &VirtReg, MCRegister PhysReg, bool IsHint, EvictionCost &MaxCost, const SmallVirtRegSet &FixedRegisters) const { // It is only possible to evict virtual register interference. @@ -941,9 +861,7 @@ bool RAGreedy::canEvictInterferenceBasedOnCost( // // This works out so a register without a cascade number is allowed to evict // anything, and it can be evicted by anything. - unsigned Cascade = ExtraRegInfo[VirtReg.reg()].Cascade; - if (!Cascade) - Cascade = NextCascade; + unsigned Cascade = ExtraInfo->getCascadeOrCurrentNext(VirtReg.reg()); EvictionCost Cost; for (MCRegUnitIterator Units(PhysReg, TRI); Units.isValid(); ++Units) { @@ -965,7 +883,7 @@ bool RAGreedy::canEvictInterferenceBasedOnCost( return false; // Never evict spill products. They cannot split or spill. - if (getStage(*Intf) == RS_Done) + if (ExtraInfo->getStage(*Intf) == RS_Done) return false; // Once a live range becomes small enough, it is urgent that we find a // register for it. This is indicated by an infinite spill weight. These @@ -980,7 +898,7 @@ bool RAGreedy::canEvictInterferenceBasedOnCost( RegClassInfo.getNumAllocatableRegs( MRI->getRegClass(Intf->reg()))); // Only evict older cascades or live ranges without a cascade. - unsigned IntfCascade = ExtraRegInfo[Intf->reg()].Cascade; + unsigned IntfCascade = ExtraInfo->getCascade(Intf->reg()); if (Cascade <= IntfCascade) { if (!Urgent) return false; @@ -1043,7 +961,7 @@ bool RAGreedy::canEvictInterferenceInRange(const LiveInterval &VirtReg, if (!Register::isVirtualRegister(Intf->reg())) return false; // Never evict spill products. They cannot split or spill. - if (getStage(*Intf) == RS_Done) + if (ExtraInfo->getStage(*Intf) == RS_Done) return false; // Would this break a satisfied hint? @@ -1106,7 +1024,7 @@ void RAGreedy::evictInterference(LiveInterval &VirtReg, MCRegister PhysReg, // Make sure that VirtReg has a cascade number, and assign that cascade // number to every evicted register. These live ranges than then only be // evicted by a newer cascade, preventing infinite loops. - unsigned Cascade = getOrAssignNewCascade(VirtReg.reg()); + unsigned Cascade = ExtraInfo->getOrAssignNewCascade(VirtReg.reg()); LLVM_DEBUG(dbgs() << "evicting " << printReg(PhysReg, TRI) << " interference: Cascade " << Cascade << '\n'); @@ -1132,10 +1050,10 @@ void RAGreedy::evictInterference(LiveInterval &VirtReg, MCRegister PhysReg, LastEvicted.addEviction(PhysReg, VirtReg.reg(), Intf->reg()); Matrix->unassign(*Intf); - assert((getCascade(Intf->reg()) < Cascade || + assert((ExtraInfo->getCascade(Intf->reg()) < Cascade || VirtReg.isSpillable() < Intf->isSpillable()) && "Cannot decrease cascade number, illegal eviction"); - setCascade(Intf->reg(), Cascade); + ExtraInfo->setCascade(Intf->reg(), Cascade); ++NumEvicted; NewVRegs.push_back(Intf->reg()); } @@ -1143,7 +1061,7 @@ void RAGreedy::evictInterference(LiveInterval &VirtReg, MCRegister PhysReg, /// Returns true if the given \p PhysReg is a callee saved register and has not /// been used for allocation yet. -bool RAGreedy::isUnusedCalleeSavedReg(MCRegister PhysReg) const { +bool RegAllocEvictionAdvisor::isUnusedCalleeSavedReg(MCRegister PhysReg) const { MCRegister CSR = RegClassInfo.getLastCalleeSavedAlias(PhysReg); if (!CSR) return false; @@ -1151,7 +1069,7 @@ bool RAGreedy::isUnusedCalleeSavedReg(MCRegister PhysReg) const { return !Matrix->isPhysRegUsed(PhysReg); } -MCRegister RAGreedy::tryFindEvictionCandidate( +MCRegister DefaultEvictionAdvisor::tryFindEvictionCandidate( LiveInterval &VirtReg, const AllocationOrder &Order, uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const { // Keep track of the cheapest interference seen so far. @@ -1225,8 +1143,8 @@ MCRegister RAGreedy::tryEvict(LiveInterval &VirtReg, AllocationOrder &Order, NamedRegionTimer T("evict", "Evict", TimerGroupName, TimerGroupDescription, TimePassesIsEnabled); - MCRegister BestPhys = - tryFindEvictionCandidate(VirtReg, Order, CostPerUseLimit, FixedRegisters); + MCRegister BestPhys = EvictAdvisor->tryFindEvictionCandidate( + VirtReg, Order, CostPerUseLimit, FixedRegisters); if (BestPhys.isValid()) evictInterference(VirtReg, BestPhys, NewVRegs); return BestPhys; @@ -1769,8 +1687,8 @@ void RAGreedy::splitAroundRegion(LiveRangeEdit &LREdit, // the ActiveBlocks list with each candidate. We need to filter out // duplicates. BitVector Todo = SA->getThroughBlocks(); - for (unsigned c = 0; c != UsedCands.size(); ++c) { - ArrayRef Blocks = GlobalCand[UsedCands[c]].ActiveBlocks; + for (unsigned UsedCand : UsedCands) { + ArrayRef Blocks = GlobalCand[UsedCand].ActiveBlocks; for (unsigned Number : Blocks) { if (!Todo.test(Number)) continue; @@ -1817,13 +1735,13 @@ void RAGreedy::splitAroundRegion(LiveRangeEdit &LREdit, const LiveInterval &Reg = LIS->getInterval(LREdit.get(I)); // Ignore old intervals from DCE. - if (getOrInitStage(Reg.reg()) != RS_New) + if (ExtraInfo->getOrInitStage(Reg.reg()) != RS_New) continue; // Remainder interval. Don't try splitting again, spill if it doesn't // allocate. if (IntvMap[I] == 0) { - setStage(Reg, RS_Spill); + ExtraInfo->setStage(Reg, RS_Spill); continue; } @@ -1834,7 +1752,7 @@ void RAGreedy::splitAroundRegion(LiveRangeEdit &LREdit, LLVM_DEBUG(dbgs() << "Main interval covers the same " << OrigBlocks << " blocks as original.\n"); // Don't allow repeated splitting as a safe guard against looping. - setStage(Reg, RS_Split2); + ExtraInfo->setStage(Reg, RS_Split2); } continue; } @@ -1899,7 +1817,7 @@ unsigned RAGreedy::calculateRegionSplitCost(LiveInterval &VirtReg, unsigned BestCand = NoCand; for (MCPhysReg PhysReg : Order) { assert(PhysReg); - if (IgnoreCSR && isUnusedCalleeSavedReg(PhysReg)) + if (IgnoreCSR && EvictAdvisor->isUnusedCalleeSavedReg(PhysReg)) continue; // Discard bad candidates before we run out of interference cache cursors. @@ -2065,8 +1983,8 @@ unsigned RAGreedy::tryBlockSplit(LiveInterval &VirtReg, AllocationOrder &Order, // goes straight to spilling, the new local ranges get to stay RS_New. for (unsigned I = 0, E = LREdit.size(); I != E; ++I) { const LiveInterval &LI = LIS->getInterval(LREdit.get(I)); - if (getOrInitStage(LI.reg()) == RS_New && IntvMap[I] == 0) - setStage(LI, RS_Spill); + if (ExtraInfo->getOrInitStage(LI.reg()) == RS_New && IntvMap[I] == 0) + ExtraInfo->setStage(LI, RS_Spill); } if (VerifyEnabled) @@ -2152,7 +2070,7 @@ RAGreedy::tryInstructionSplit(LiveInterval &VirtReg, AllocationOrder &Order, SE->finish(&IntvMap); DebugVars->splitRegister(VirtReg.reg(), LREdit.regs(), *LIS); // Assign all new registers to RS_Spill. This was the last chance. - setStage(LREdit.begin(), LREdit.end(), RS_Spill); + ExtraInfo->setStage(LREdit.begin(), LREdit.end(), RS_Spill); return 0; } @@ -2320,7 +2238,7 @@ unsigned RAGreedy::tryLocalSplit(LiveInterval &VirtReg, AllocationOrder &Order, // These rules allow a 3 -> 2+3 split once, which we need. They also prevent // excessive splitting and infinite loops. // - bool ProgressRequired = getStage(VirtReg) >= RS_Split2; + bool ProgressRequired = ExtraInfo->getStage(VirtReg) >= RS_Split2; // Best split candidate. unsigned BestBefore = NumGaps; @@ -2456,7 +2374,7 @@ unsigned RAGreedy::tryLocalSplit(LiveInterval &VirtReg, AllocationOrder &Order, assert(!ProgressRequired && "Didn't make progress when it was required."); for (unsigned I = 0, E = IntvMap.size(); I != E; ++I) if (IntvMap[I] == 1) { - setStage(LIS->getInterval(LREdit.get(I)), RS_Split2); + ExtraInfo->setStage(LIS->getInterval(LREdit.get(I)), RS_Split2); LLVM_DEBUG(dbgs() << ' ' << printReg(LREdit.get(I))); } LLVM_DEBUG(dbgs() << '\n'); @@ -2477,7 +2395,7 @@ unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order, SmallVectorImpl &NewVRegs, const SmallVirtRegSet &FixedRegisters) { // Ranges must be Split2 or less. - if (getStage(VirtReg) >= RS_Spill) + if (ExtraInfo->getStage(VirtReg) >= RS_Spill) return 0; // Local intervals are handled separately. @@ -2499,7 +2417,7 @@ unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order, // First try to split around a region spanning multiple blocks. RS_Split2 // ranges already made dubious progress with region splitting, so they go // straight to single block splitting. - if (getStage(VirtReg) < RS_Split2) { + if (ExtraInfo->getStage(VirtReg) < RS_Split2) { MCRegister PhysReg = tryRegionSplit(VirtReg, Order, NewVRegs); if (PhysReg || !NewVRegs.empty()) return PhysReg; @@ -2551,7 +2469,7 @@ bool RAGreedy::mayRecolorAllInterferences( // it would not be recolorable as it is in the same state as VirtReg. // However, if VirtReg has tied defs and Intf doesn't, then // there is still a point in examining if it can be recolorable. - if (((getStage(*Intf) == RS_Done && + if (((ExtraInfo->getStage(*Intf) == RS_Done && MRI->getRegClass(Intf->reg()) == CurRC) && !(hasTiedDef(MRI, VirtReg.reg()) && !hasTiedDef(MRI, Intf->reg()))) || @@ -2615,7 +2533,7 @@ unsigned RAGreedy::tryLastChanceRecoloring(LiveInterval &VirtReg, LLVM_DEBUG(dbgs() << "Try last chance recoloring for " << VirtReg << '\n'); // Ranges must be Done. - assert((getStage(VirtReg) >= RS_Done || !VirtReg.isSpillable()) && + assert((ExtraInfo->getStage(VirtReg) >= RS_Done || !VirtReg.isSpillable()) && "Last chance recoloring should really be last chance"); // Set the max depth to LastChanceRecoloringMaxDepth. // We may want to reconsider that if we end up with a too large search space @@ -2806,7 +2724,7 @@ MCRegister RAGreedy::tryAssignCSRFirstTime(LiveInterval &VirtReg, AllocationOrder &Order, MCRegister PhysReg, uint8_t &CostPerUseLimit, SmallVectorImpl &NewVRegs) { - if (getStage(VirtReg) == RS_Spill && VirtReg.isSpillable()) { + if (ExtraInfo->getStage(VirtReg) == RS_Spill && VirtReg.isSpillable()) { // We choose spill over using the CSR for the first time if the spill cost // is lower than CSRCost. SA->analyze(&VirtReg); @@ -2818,7 +2736,7 @@ RAGreedy::tryAssignCSRFirstTime(LiveInterval &VirtReg, AllocationOrder &Order, CostPerUseLimit = 1; return 0; } - if (getStage(VirtReg) < RS_Split) { + if (ExtraInfo->getStage(VirtReg) < RS_Split) { // We choose pre-splitting over using the CSR for the first time if // the cost of splitting is lower than CSRCost. SA->analyze(&VirtReg); @@ -3051,8 +2969,8 @@ MCRegister RAGreedy::selectOrSplitImpl(LiveInterval &VirtReg, // When NewVRegs is not empty, we may have made decisions such as evicting // a virtual register, go with the earlier decisions and use the physical // register. - if (CSRCost.getFrequency() && isUnusedCalleeSavedReg(PhysReg) && - NewVRegs.empty()) { + if (CSRCost.getFrequency() && + EvictAdvisor->isUnusedCalleeSavedReg(PhysReg) && NewVRegs.empty()) { MCRegister CSRReg = tryAssignCSRFirstTime(VirtReg, Order, PhysReg, CostPerUseLimit, NewVRegs); if (CSRReg || !NewVRegs.empty()) @@ -3063,9 +2981,9 @@ MCRegister RAGreedy::selectOrSplitImpl(LiveInterval &VirtReg, return PhysReg; } - LiveRangeStage Stage = getStage(VirtReg); + LiveRangeStage Stage = ExtraInfo->getStage(VirtReg); LLVM_DEBUG(dbgs() << StageName[Stage] << " Cascade " - << getCascade(VirtReg.reg()) << '\n'); + << ExtraInfo->getCascade(VirtReg.reg()) << '\n'); // Try to evict a less worthy live range, but only for ranges from the primary // queue. The RS_Split ranges already failed to do this, and they should not @@ -3094,7 +3012,7 @@ MCRegister RAGreedy::selectOrSplitImpl(LiveInterval &VirtReg, // Wait until the second time, when all smaller ranges have been allocated. // This gives a better picture of the interference to split around. if (Stage < RS_Split) { - setStage(VirtReg, RS_Split); + ExtraInfo->setStage(VirtReg, RS_Split); LLVM_DEBUG(dbgs() << "wait for second round\n"); NewVRegs.push_back(VirtReg.reg()); return 0; @@ -3120,12 +3038,12 @@ MCRegister RAGreedy::selectOrSplitImpl(LiveInterval &VirtReg, // Finally spill VirtReg itself. if ((EnableDeferredSpilling || TRI->shouldUseDeferredSpillingForVirtReg(*MF, VirtReg)) && - getStage(VirtReg) < RS_Memory) { + ExtraInfo->getStage(VirtReg) < RS_Memory) { // TODO: This is experimental and in particular, we do not model // the live range splitting done by spilling correctly. // We would need a deep integration with the spiller to do the // right thing here. Anyway, that is still good for early testing. - setStage(VirtReg, RS_Memory); + ExtraInfo->setStage(VirtReg, RS_Memory); LLVM_DEBUG(dbgs() << "Do as if this register is in memory\n"); NewVRegs.push_back(VirtReg.reg()); } else { @@ -3133,7 +3051,7 @@ MCRegister RAGreedy::selectOrSplitImpl(LiveInterval &VirtReg, TimerGroupDescription, TimePassesIsEnabled); LiveRangeEdit LRE(&VirtReg, NewVRegs, *MF, *LIS, VRM, this, &DeadRemats); spiller().spill(LRE); - setStage(NewVRegs.begin(), NewVRegs.end(), RS_Done); + ExtraInfo->setStage(NewVRegs.begin(), NewVRegs.end(), RS_Done); // Tell LiveDebugVariables about the new ranges. Ranges not being covered by // the new regs are kept in LDV (still mapping to the old register), until @@ -3316,10 +3234,6 @@ bool RAGreedy::runOnMachineFunction(MachineFunction &mf) { TII = MF->getSubtarget().getInstrInfo(); RCI.runOnMachineFunction(mf); - EnableLocalReassign = EnableLocalReassignment || - MF->getSubtarget().enableRALocalReassignment( - MF->getTarget().getOptLevel()); - EnableAdvancedRASplitCost = ConsiderLocalIntervalCost.getNumOccurrences() ? ConsiderLocalIntervalCost @@ -3354,8 +3268,9 @@ bool RAGreedy::runOnMachineFunction(MachineFunction &mf) { SA.reset(new SplitAnalysis(*VRM, *LIS, *Loops)); SE.reset(new SplitEditor(*SA, *AA, *LIS, *VRM, *DomTree, *MBFI, *VRAI)); - ExtraRegInfo.clear(); - NextCascade = 1; + ExtraInfo.emplace(); + EvictAdvisor = getAnalysis().getAdvisor( + *MF, Matrix, LIS, VRM, RegClassInfo, &*ExtraInfo); IntfCache.init(MF, Matrix->getLiveUnions(), Indexes, LIS, TRI); GlobalCand.resize(32); // This will grow as needed. SetOfBrokenHints.clear(); diff --git a/llvm/lib/CodeGen/RegAllocPBQP.cpp b/llvm/lib/CodeGen/RegAllocPBQP.cpp index b22eb080791e..93be8f689d57 100644 --- a/llvm/lib/CodeGen/RegAllocPBQP.cpp +++ b/llvm/lib/CodeGen/RegAllocPBQP.cpp @@ -623,8 +623,8 @@ void RegAllocPBQP::initializeGraph(PBQPRAGraph &G, VirtRegMap &VRM, // Compute an initial allowed set for the current vreg. std::vector VRegAllowed; ArrayRef RawPRegOrder = TRC->getRawAllocationOrder(MF); - for (unsigned I = 0; I != RawPRegOrder.size(); ++I) { - MCRegister PReg(RawPRegOrder[I]); + for (MCPhysReg R : RawPRegOrder) { + MCRegister PReg(R); if (MRI.isReserved(PReg)) continue; diff --git a/llvm/lib/CodeGen/RegAllocScore.cpp b/llvm/lib/CodeGen/RegAllocScore.cpp new file mode 100644 index 000000000000..740890831617 --- /dev/null +++ b/llvm/lib/CodeGen/RegAllocScore.cpp @@ -0,0 +1,124 @@ +//===- RegAllocScore.cpp - evaluate regalloc policy quality ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// Calculate a measure of the register allocation policy quality. This is used +/// to construct a reward for the training of the ML-driven allocation policy. +/// Currently, the score is the sum of the machine basic block frequency-weighed +/// number of loads, stores, copies, and remat instructions, each factored with +/// a relative weight. +//===----------------------------------------------------------------------===// + +#include "RegAllocScore.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include +#include +#include +#include + +using namespace llvm; +cl::opt CopyWeight("regalloc-copy-weight", cl::init(0.2), cl::Hidden); +cl::opt LoadWeight("regalloc-load-weight", cl::init(4.0), cl::Hidden); +cl::opt StoreWeight("regalloc-store-weight", cl::init(1.0), cl::Hidden); +cl::opt CheapRematWeight("regalloc-cheap-remat-weight", cl::init(0.2), + cl::Hidden); +cl::opt ExpensiveRematWeight("regalloc-expensive-remat-weight", + cl::init(1.0), cl::Hidden); +#define DEBUG_TYPE "regalloc-score" + +RegAllocScore &RegAllocScore::operator+=(const RegAllocScore &Other) { + CopyCounts += Other.copyCounts(); + LoadCounts += Other.loadCounts(); + StoreCounts += Other.storeCounts(); + LoadStoreCounts += Other.loadStoreCounts(); + CheapRematCounts += Other.cheapRematCounts(); + ExpensiveRematCounts += Other.expensiveRematCounts(); + return *this; +} + +bool RegAllocScore::operator==(const RegAllocScore &Other) const { + return copyCounts() == Other.copyCounts() && + loadCounts() == Other.loadCounts() && + storeCounts() == Other.storeCounts() && + loadStoreCounts() == Other.loadStoreCounts() && + cheapRematCounts() == Other.cheapRematCounts() && + expensiveRematCounts() == Other.expensiveRematCounts(); +} + +bool RegAllocScore::operator!=(const RegAllocScore &Other) const { + return !(*this == Other); +} + +double RegAllocScore::getScore() const { + double Ret = 0.0; + Ret += CopyWeight * copyCounts(); + Ret += LoadWeight * loadCounts(); + Ret += StoreWeight * storeCounts(); + Ret += (LoadWeight + StoreWeight) * loadStoreCounts(); + Ret += CheapRematWeight * cheapRematCounts(); + Ret += ExpensiveRematWeight * expensiveRematCounts(); + + return Ret; +} + +RegAllocScore +llvm::calculateRegAllocScore(const MachineFunction &MF, + const MachineBlockFrequencyInfo &MBFI, + AAResults &AAResults) { + return calculateRegAllocScore( + MF, + [&](const MachineBasicBlock &MBB) { + return MBFI.getBlockFreqRelativeToEntryBlock(&MBB); + }, + [&](const MachineInstr &MI) { + return MF.getSubtarget().getInstrInfo()->isTriviallyReMaterializable( + MI, &AAResults); + }); +} + +RegAllocScore llvm::calculateRegAllocScore( + const MachineFunction &MF, + llvm::function_ref GetBBFreq, + llvm::function_ref + IsTriviallyRematerializable) { + RegAllocScore Total; + + for (const MachineBasicBlock &MBB : MF) { + double BlockFreqRelativeToEntrypoint = GetBBFreq(MBB); + RegAllocScore MBBScore; + + for (const MachineInstr &MI : MBB) { + if (MI.isDebugInstr() || MI.isKill() || MI.isInlineAsm()) { + continue; + } + if (MI.isCopy()) { + MBBScore.onCopy(BlockFreqRelativeToEntrypoint); + } else if (IsTriviallyRematerializable(MI)) { + if (MI.getDesc().isAsCheapAsAMove()) { + MBBScore.onCheapRemat(BlockFreqRelativeToEntrypoint); + } else { + MBBScore.onExpensiveRemat(BlockFreqRelativeToEntrypoint); + } + } else if (MI.mayLoad() && MI.mayStore()) { + MBBScore.onLoadStore(BlockFreqRelativeToEntrypoint); + } else if (MI.mayLoad()) { + MBBScore.onLoad(BlockFreqRelativeToEntrypoint); + } else if (MI.mayStore()) { + MBBScore.onStore(BlockFreqRelativeToEntrypoint); + } + } + Total += MBBScore; + } + return Total; +} diff --git a/llvm/lib/CodeGen/RegAllocScore.h b/llvm/lib/CodeGen/RegAllocScore.h new file mode 100644 index 000000000000..3c28bb61189d --- /dev/null +++ b/llvm/lib/CodeGen/RegAllocScore.h @@ -0,0 +1,80 @@ +//==- RegAllocScore.h - evaluate regalloc policy quality ----------*-C++-*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// Calculate a measure of the register allocation policy quality. This is used +/// to construct a reward for the training of the ML-driven allocation policy. +/// Currently, the score is the sum of the machine basic block frequency-weighed +/// number of loads, stores, copies, and remat instructions, each factored with +/// a relative weight. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_REGALLOCSCORE_H_ +#define LLVM_CODEGEN_REGALLOCSCORE_H_ + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Analysis/ProfileSummaryInfo.h" +#include "llvm/Analysis/Utils/TFUtils.h" +#include "llvm/CodeGen/MachineBlockFrequencyInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/Module.h" +#include +#include +#include + +namespace llvm { + +/// Regalloc score. +class RegAllocScore final { + double CopyCounts = 0.0; + double LoadCounts = 0.0; + double StoreCounts = 0.0; + double CheapRematCounts = 0.0; + double LoadStoreCounts = 0.0; + double ExpensiveRematCounts = 0.0; + +public: + RegAllocScore() = default; + RegAllocScore(const RegAllocScore &) = default; + + double copyCounts() const { return CopyCounts; } + double loadCounts() const { return LoadCounts; } + double storeCounts() const { return StoreCounts; } + double loadStoreCounts() const { return LoadStoreCounts; } + double expensiveRematCounts() const { return ExpensiveRematCounts; } + double cheapRematCounts() const { return CheapRematCounts; } + + void onCopy(double Freq) { CopyCounts += Freq; } + void onLoad(double Freq) { LoadCounts += Freq; } + void onStore(double Freq) { StoreCounts += Freq; } + void onLoadStore(double Freq) { LoadStoreCounts += Freq; } + void onExpensiveRemat(double Freq) { ExpensiveRematCounts += Freq; } + void onCheapRemat(double Freq) { CheapRematCounts += Freq; } + + RegAllocScore &operator+=(const RegAllocScore &Other); + bool operator==(const RegAllocScore &Other) const; + bool operator!=(const RegAllocScore &Other) const; + double getScore() const; +}; + +/// Calculate a score. When comparing 2 scores for the same function but +/// different policies, the better policy would have a smaller score. +/// The implementation is the overload below (which is also easily unittestable) +RegAllocScore calculateRegAllocScore(const MachineFunction &MF, + const MachineBlockFrequencyInfo &MBFI, + AAResults &AAResults); + +/// Implementation of the above, which is also more easily unittestable. +RegAllocScore calculateRegAllocScore( + const MachineFunction &MF, + llvm::function_ref GetBBFreq, + llvm::function_ref IsTriviallyRematerializable); +} // end namespace llvm + +#endif // LLVM_CODEGEN_REGALLOCSCORE_H_ diff --git a/llvm/lib/CodeGen/RegisterClassInfo.cpp b/llvm/lib/CodeGen/RegisterClassInfo.cpp index 797899fb5b86..65a65b9cae95 100644 --- a/llvm/lib/CodeGen/RegisterClassInfo.cpp +++ b/llvm/lib/CodeGen/RegisterClassInfo.cpp @@ -109,8 +109,7 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const { // FIXME: Once targets reserve registers instead of removing them from the // allocation order, we can simply use begin/end here. ArrayRef RawOrder = RC->getRawAllocationOrder(*MF); - for (unsigned i = 0; i != RawOrder.size(); ++i) { - unsigned PhysReg = RawOrder[i]; + for (unsigned PhysReg : RawOrder) { // Remove reserved registers from the allocation order. if (Reserved.test(PhysReg)) continue; diff --git a/llvm/lib/CodeGen/RegisterCoalescer.cpp b/llvm/lib/CodeGen/RegisterCoalescer.cpp index 4c8534cf2d01..a917b0d27d4a 100644 --- a/llvm/lib/CodeGen/RegisterCoalescer.cpp +++ b/llvm/lib/CodeGen/RegisterCoalescer.cpp @@ -4067,13 +4067,13 @@ void RegisterCoalescer::joinAllIntervals() { // Coalesce intervals in MBB priority order. unsigned CurrDepth = std::numeric_limits::max(); - for (unsigned i = 0, e = MBBs.size(); i != e; ++i) { + for (MBBPriorityInfo &MBB : MBBs) { // Try coalescing the collected local copies for deeper loops. - if (JoinGlobalCopies && MBBs[i].Depth < CurrDepth) { + if (JoinGlobalCopies && MBB.Depth < CurrDepth) { coalesceLocals(); - CurrDepth = MBBs[i].Depth; + CurrDepth = MBB.Depth; } - copyCoalesceInMBB(MBBs[i].MBB); + copyCoalesceInMBB(MBB.MBB); } lateLiveIntervalUpdate(); coalesceLocals(); diff --git a/llvm/lib/CodeGen/RemoveRedundantDebugValues.cpp b/llvm/lib/CodeGen/RemoveRedundantDebugValues.cpp index de6129a912d3..49859aeec78b 100644 --- a/llvm/lib/CodeGen/RemoveRedundantDebugValues.cpp +++ b/llvm/lib/CodeGen/RemoveRedundantDebugValues.cpp @@ -159,20 +159,17 @@ static bool reduceDbgValsBackwardScan(MachineBasicBlock &MBB) { SmallVector DbgValsToBeRemoved; SmallDenseSet VariableSet; - for (MachineBasicBlock::reverse_iterator I = MBB.rbegin(), E = MBB.rend(); - I != E; ++I) { - MachineInstr *MI = &*I; - - if (MI->isDebugValue()) { - DebugVariable Var(MI->getDebugVariable(), MI->getDebugExpression(), - MI->getDebugLoc()->getInlinedAt()); + for (MachineInstr &MI : llvm::reverse(MBB)) { + if (MI.isDebugValue()) { + DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(), + MI.getDebugLoc()->getInlinedAt()); auto R = VariableSet.insert(Var); // If it is a DBG_VALUE describing a constant as: // DBG_VALUE 0, ... // we just don't consider such instructions as candidates // for redundant removal. - if (MI->isNonListDebugValue()) { - MachineOperand &Loc = MI->getDebugOperand(0); + if (MI.isNonListDebugValue()) { + MachineOperand &Loc = MI.getDebugOperand(0); if (!Loc.isReg()) { // If we have already encountered this variable, just stop // tracking it. @@ -185,7 +182,7 @@ static bool reduceDbgValsBackwardScan(MachineBasicBlock &MBB) { // We have already encountered the value for this variable, // so this one can be deleted. if (!R.second) - DbgValsToBeRemoved.push_back(MI); + DbgValsToBeRemoved.push_back(&MI); continue; } diff --git a/llvm/lib/CodeGen/SafeStack.cpp b/llvm/lib/CodeGen/SafeStack.cpp index 50d9d64bfcfd..3d8a7eecce18 100644 --- a/llvm/lib/CodeGen/SafeStack.cpp +++ b/llvm/lib/CodeGen/SafeStack.cpp @@ -521,8 +521,7 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack( StackLayout SSL(StackAlignment); if (StackGuardSlot) { Type *Ty = StackGuardSlot->getAllocatedType(); - uint64_t Align = - std::max(DL.getPrefTypeAlignment(Ty), StackGuardSlot->getAlignment()); + Align Align = std::max(DL.getPrefTypeAlign(Ty), StackGuardSlot->getAlign()); SSL.addObject(StackGuardSlot, getStaticAllocaAllocationSize(StackGuardSlot), Align, SSC.getFullLiveRange()); } @@ -534,8 +533,9 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack( Size = 1; // Don't create zero-sized stack objects. // Ensure the object is properly aligned. - uint64_t Align = - std::max(DL.getPrefTypeAlignment(Ty), Arg->getParamAlignment()); + Align Align = DL.getPrefTypeAlign(Ty); + if (auto A = Arg->getParamAlign()) + Align = std::max(Align, *A); SSL.addObject(Arg, Size, Align, SSC.getFullLiveRange()); } @@ -546,24 +546,24 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack( Size = 1; // Don't create zero-sized stack objects. // Ensure the object is properly aligned. - uint64_t Align = std::max(DL.getPrefTypeAlignment(Ty), AI->getAlignment()); + Align Align = std::max(DL.getPrefTypeAlign(Ty), AI->getAlign()); SSL.addObject(AI, Size, Align, ClColoring ? SSC.getLiveRange(AI) : NoColoringRange); } SSL.computeLayout(); - uint64_t FrameAlignment = SSL.getFrameAlignment(); + Align FrameAlignment = SSL.getFrameAlignment(); // FIXME: tell SSL that we start at a less-then-MaxAlignment aligned location // (AlignmentSkew). if (FrameAlignment > StackAlignment) { // Re-align the base pointer according to the max requested alignment. - assert(isPowerOf2_64(FrameAlignment)); IRB.SetInsertPoint(BasePointer->getNextNode()); BasePointer = cast(IRB.CreateIntToPtr( - IRB.CreateAnd(IRB.CreatePtrToInt(BasePointer, IntPtrTy), - ConstantInt::get(IntPtrTy, ~uint64_t(FrameAlignment - 1))), + IRB.CreateAnd( + IRB.CreatePtrToInt(BasePointer, IntPtrTy), + ConstantInt::get(IntPtrTy, ~(FrameAlignment.value() - 1))), StackPtrTy)); } diff --git a/llvm/lib/CodeGen/SafeStackLayout.cpp b/llvm/lib/CodeGen/SafeStackLayout.cpp index 7cdda7743c16..602afcfa9001 100644 --- a/llvm/lib/CodeGen/SafeStackLayout.cpp +++ b/llvm/lib/CodeGen/SafeStackLayout.cpp @@ -37,7 +37,7 @@ LLVM_DUMP_METHOD void StackLayout::print(raw_ostream &OS) { } } -void StackLayout::addObject(const Value *V, unsigned Size, uint64_t Alignment, +void StackLayout::addObject(const Value *V, unsigned Size, Align Alignment, const StackLifetime::LiveRange &Range) { StackObjects.push_back({V, Size, Alignment, Range}); ObjectAlignments[V] = Alignment; @@ -45,7 +45,7 @@ void StackLayout::addObject(const Value *V, unsigned Size, uint64_t Alignment, } static unsigned AdjustStackOffset(unsigned Offset, unsigned Size, - uint64_t Alignment) { + Align Alignment) { return alignTo(Offset + Size, Alignment) - Size; } @@ -62,7 +62,8 @@ void StackLayout::layoutObject(StackObject &Obj) { } LLVM_DEBUG(dbgs() << "Layout: size " << Obj.Size << ", align " - << Obj.Alignment << ", range " << Obj.Range << "\n"); + << Obj.Alignment.value() << ", range " << Obj.Range + << "\n"); assert(Obj.Alignment <= MaxAlignment); unsigned Start = AdjustStackOffset(0, Obj.Size, Obj.Alignment); unsigned End = Start + Obj.Size; diff --git a/llvm/lib/CodeGen/SafeStackLayout.h b/llvm/lib/CodeGen/SafeStackLayout.h index b72450e57080..4ac7af2059f5 100644 --- a/llvm/lib/CodeGen/SafeStackLayout.h +++ b/llvm/lib/CodeGen/SafeStackLayout.h @@ -22,7 +22,7 @@ namespace safestack { /// Compute the layout of an unsafe stack frame. class StackLayout { - uint64_t MaxAlignment; + Align MaxAlignment; struct StackRegion { unsigned Start; @@ -40,14 +40,14 @@ class StackLayout { struct StackObject { const Value *Handle; unsigned Size; - uint64_t Alignment; + Align Alignment; StackLifetime::LiveRange Range; }; SmallVector StackObjects; DenseMap ObjectOffsets; - DenseMap ObjectAlignments; + DenseMap ObjectAlignments; void layoutObject(StackObject &Obj); @@ -56,7 +56,7 @@ public: /// Add an object to the stack frame. Value pointer is opaque and used as a /// handle to retrieve the object's offset in the frame later. - void addObject(const Value *V, unsigned Size, uint64_t Alignment, + void addObject(const Value *V, unsigned Size, Align Alignment, const StackLifetime::LiveRange &Range); /// Run the layout computation for all previously added objects. @@ -66,13 +66,13 @@ public: unsigned getObjectOffset(const Value *V) { return ObjectOffsets[V]; } /// Returns the alignment of the object - uint64_t getObjectAlignment(const Value *V) { return ObjectAlignments[V]; } + Align getObjectAlignment(const Value *V) { return ObjectAlignments[V]; } /// Returns the size of the entire frame. unsigned getFrameSize() { return Regions.empty() ? 0 : Regions.back().End; } /// Returns the alignment of the frame. - uint64_t getFrameAlignment() { return MaxAlignment; } + Align getFrameAlignment() { return MaxAlignment; } void print(raw_ostream &OS); }; diff --git a/llvm/lib/CodeGen/ScheduleDAG.cpp b/llvm/lib/CodeGen/ScheduleDAG.cpp index ef3afab2b730..696b29018ae6 100644 --- a/llvm/lib/CodeGen/ScheduleDAG.cpp +++ b/llvm/lib/CodeGen/ScheduleDAG.cpp @@ -618,8 +618,8 @@ std::vector ScheduleDAGTopologicalSort::GetSubGraph(const SUnit &StartSU, do { const SUnit *SU = WorkList.back(); WorkList.pop_back(); - for (int I = SU->Succs.size()-1; I >= 0; --I) { - const SUnit *Succ = SU->Succs[I].getSUnit(); + for (const SDep &SD : llvm::reverse(SU->Succs)) { + const SUnit *Succ = SD.getSUnit(); unsigned s = Succ->NodeNum; // Edges to non-SUnits are allowed but ignored (e.g. ExitSU). if (Succ->isBoundaryNode()) @@ -652,8 +652,8 @@ std::vector ScheduleDAGTopologicalSort::GetSubGraph(const SUnit &StartSU, do { const SUnit *SU = WorkList.back(); WorkList.pop_back(); - for (int I = SU->Preds.size()-1; I >= 0; --I) { - const SUnit *Pred = SU->Preds[I].getSUnit(); + for (const SDep &SD : llvm::reverse(SU->Preds)) { + const SUnit *Pred = SD.getSUnit(); unsigned s = Pred->NodeNum; // Edges to non-SUnits are allowed but ignored (e.g. EntrySU). if (Pred->isBoundaryNode()) diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index df5a041b87cd..067ad819e0d2 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -487,10 +487,7 @@ namespace { SDValue visitFCEIL(SDNode *N); SDValue visitFTRUNC(SDNode *N); SDValue visitFFLOOR(SDNode *N); - SDValue visitFMINNUM(SDNode *N); - SDValue visitFMAXNUM(SDNode *N); - SDValue visitFMINIMUM(SDNode *N); - SDValue visitFMAXIMUM(SDNode *N); + SDValue visitFMinMax(SDNode *N); SDValue visitBRCOND(SDNode *N); SDValue visitBR_CC(SDNode *N); SDValue visitLOAD(SDNode *N); @@ -1701,10 +1698,10 @@ SDValue DAGCombiner::visit(SDNode *N) { case ISD::FNEG: return visitFNEG(N); case ISD::FABS: return visitFABS(N); case ISD::FFLOOR: return visitFFLOOR(N); - case ISD::FMINNUM: return visitFMINNUM(N); - case ISD::FMAXNUM: return visitFMAXNUM(N); - case ISD::FMINIMUM: return visitFMINIMUM(N); - case ISD::FMAXIMUM: return visitFMAXIMUM(N); + case ISD::FMINNUM: + case ISD::FMAXNUM: + case ISD::FMINIMUM: + case ISD::FMAXIMUM: return visitFMinMax(N); case ISD::FCEIL: return visitFCEIL(N); case ISD::FTRUNC: return visitFTRUNC(N); case ISD::BRCOND: return visitBRCOND(N); @@ -2260,6 +2257,21 @@ SDValue DAGCombiner::visitADDLike(SDNode *N) { EVT VT = N0.getValueType(); SDLoc DL(N); + // fold (add x, undef) -> undef + if (N0.isUndef()) + return N0; + if (N1.isUndef()) + return N1; + + // fold (add c1, c2) -> c1+c2 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::ADD, DL, VT, {N0, N1})) + return C; + + // canonicalize constant to RHS + if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && + !DAG.isConstantIntBuildVectorOrConstantInt(N1)) + return DAG.getNode(ISD::ADD, DL, VT, N1, N0); + // fold vector ops if (VT.isVector()) { if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) @@ -2268,23 +2280,6 @@ SDValue DAGCombiner::visitADDLike(SDNode *N) { // fold (add x, 0) -> x, vector edition if (ISD::isConstantSplatVectorAllZeros(N1.getNode())) return N0; - if (ISD::isConstantSplatVectorAllZeros(N0.getNode())) - return N1; - } - - // fold (add x, undef) -> undef - if (N0.isUndef()) - return N0; - - if (N1.isUndef()) - return N1; - - if (DAG.isConstantIntBuildVectorOrConstantInt(N0)) { - // canonicalize constant to RHS - if (!DAG.isConstantIntBuildVectorOrConstantInt(N1)) - return DAG.getNode(ISD::ADD, DL, VT, N1, N0); - // fold (add c1, c2) -> c1+c2 - return DAG.FoldConstantArithmetic(ISD::ADD, DL, VT, {N0, N1}); } // fold (add x, 0) -> x @@ -2554,6 +2549,19 @@ SDValue DAGCombiner::visitADDSAT(SDNode *N) { EVT VT = N0.getValueType(); SDLoc DL(N); + // fold (add_sat x, undef) -> -1 + if (N0.isUndef() || N1.isUndef()) + return DAG.getAllOnesConstant(DL, VT); + + // fold (add_sat c1, c2) -> c3 + if (SDValue C = DAG.FoldConstantArithmetic(Opcode, DL, VT, {N0, N1})) + return C; + + // canonicalize constant to RHS + if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && + !DAG.isConstantIntBuildVectorOrConstantInt(N1)) + return DAG.getNode(Opcode, DL, VT, N1, N0); + // fold vector ops if (VT.isVector()) { // TODO SimplifyVBinOp @@ -2561,20 +2569,6 @@ SDValue DAGCombiner::visitADDSAT(SDNode *N) { // fold (add_sat x, 0) -> x, vector edition if (ISD::isConstantSplatVectorAllZeros(N1.getNode())) return N0; - if (ISD::isConstantSplatVectorAllZeros(N0.getNode())) - return N1; - } - - // fold (add_sat x, undef) -> -1 - if (N0.isUndef() || N1.isUndef()) - return DAG.getAllOnesConstant(DL, VT); - - if (DAG.isConstantIntBuildVectorOrConstantInt(N0)) { - // canonicalize constant to RHS - if (!DAG.isConstantIntBuildVectorOrConstantInt(N1)) - return DAG.getNode(Opcode, DL, VT, N1, N0); - // fold (add_sat c1, c2) -> c3 - return DAG.FoldConstantArithmetic(Opcode, DL, VT, {N0, N1}); } // fold (add_sat x, 0) -> x @@ -3260,6 +3254,15 @@ SDValue DAGCombiner::visitSUB(SDNode *N) { EVT VT = N0.getValueType(); SDLoc DL(N); + // fold (sub x, x) -> 0 + // FIXME: Refactor this and xor and other similar operations together. + if (N0 == N1) + return tryFoldToZero(DL, TLI, VT, DAG, LegalOperations); + + // fold (sub c1, c2) -> c3 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::SUB, DL, VT, {N0, N1})) + return C; + // fold vector ops if (VT.isVector()) { if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) @@ -3270,15 +3273,6 @@ SDValue DAGCombiner::visitSUB(SDNode *N) { return N0; } - // fold (sub x, x) -> 0 - // FIXME: Refactor this and xor and other similar operations together. - if (N0 == N1) - return tryFoldToZero(DL, TLI, VT, DAG, LegalOperations); - - // fold (sub c1, c2) -> c3 - if (SDValue C = DAG.FoldConstantArithmetic(ISD::SUB, DL, VT, {N0, N1})) - return C; - if (SDValue NewSel = foldBinOpIntoSelect(N)) return NewSel; @@ -3611,15 +3605,6 @@ SDValue DAGCombiner::visitSUBSAT(SDNode *N) { EVT VT = N0.getValueType(); SDLoc DL(N); - // fold vector ops - if (VT.isVector()) { - // TODO SimplifyVBinOp - - // fold (sub_sat x, 0) -> x, vector edition - if (ISD::isConstantSplatVectorAllZeros(N1.getNode())) - return N0; - } - // fold (sub_sat x, undef) -> 0 if (N0.isUndef() || N1.isUndef()) return DAG.getConstant(0, DL, VT); @@ -3632,6 +3617,15 @@ SDValue DAGCombiner::visitSUBSAT(SDNode *N) { if (SDValue C = DAG.FoldConstantArithmetic(N->getOpcode(), DL, VT, {N0, N1})) return C; + // fold vector ops + if (VT.isVector()) { + // TODO SimplifyVBinOp + + // fold (sub_sat x, 0) -> x, vector edition + if (ISD::isConstantSplatVectorAllZeros(N1.getNode())) + return N0; + } + // fold (sub_sat x, 0) -> x if (isNullConstant(N1)) return N0; @@ -3781,6 +3775,15 @@ SDValue DAGCombiner::visitMUL(SDNode *N) { if (N0.isUndef() || N1.isUndef()) return DAG.getConstant(0, SDLoc(N), VT); + // fold (mul c1, c2) -> c1*c2 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::MUL, SDLoc(N), VT, {N0, N1})) + return C; + + // canonicalize constant to RHS (vector doesn't have to splat) + if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && + !DAG.isConstantIntBuildVectorOrConstantInt(N1)) + return DAG.getNode(ISD::MUL, SDLoc(N), VT, N1, N0); + bool N1IsConst = false; bool N1IsOpaqueConst = false; APInt ConstValue1; @@ -3802,15 +3805,6 @@ SDValue DAGCombiner::visitMUL(SDNode *N) { } } - // fold (mul c1, c2) -> c1*c2 - if (SDValue C = DAG.FoldConstantArithmetic(ISD::MUL, SDLoc(N), VT, {N0, N1})) - return C; - - // canonicalize constant to RHS (vector doesn't have to splat) - if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && - !DAG.isConstantIntBuildVectorOrConstantInt(N1)) - return DAG.getNode(ISD::MUL, SDLoc(N), VT, N1, N0); - // fold (mul x, 0) -> 0 if (N1IsConst && ConstValue1.isZero()) return N1; @@ -4140,17 +4134,17 @@ SDValue DAGCombiner::visitSDIV(SDNode *N) { EVT CCVT = getSetCCResultType(VT); SDLoc DL(N); + // fold (sdiv c1, c2) -> c1/c2 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::SDIV, DL, VT, {N0, N1})) + return C; + // fold vector ops if (VT.isVector()) if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) return FoldedVOp; - // fold (sdiv c1, c2) -> c1/c2 - ConstantSDNode *N1C = isConstOrConstSplat(N1); - if (SDValue C = DAG.FoldConstantArithmetic(ISD::SDIV, DL, VT, {N0, N1})) - return C; - // fold (sdiv X, -1) -> 0-X + ConstantSDNode *N1C = isConstOrConstSplat(N1); if (N1C && N1C->isAllOnes()) return DAG.getNode(ISD::SUB, DL, VT, DAG.getConstant(0, DL, VT), N0); @@ -4284,17 +4278,17 @@ SDValue DAGCombiner::visitUDIV(SDNode *N) { EVT CCVT = getSetCCResultType(VT); SDLoc DL(N); + // fold (udiv c1, c2) -> c1/c2 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::UDIV, DL, VT, {N0, N1})) + return C; + // fold vector ops if (VT.isVector()) if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) return FoldedVOp; - // fold (udiv c1, c2) -> c1/c2 - ConstantSDNode *N1C = isConstOrConstSplat(N1); - if (SDValue C = DAG.FoldConstantArithmetic(ISD::UDIV, DL, VT, {N0, N1})) - return C; - // fold (udiv X, -1) -> select(X == -1, 1, 0) + ConstantSDNode *N1C = isConstOrConstSplat(N1); if (N1C && N1C->isAllOnes()) return DAG.getSelect(DL, VT, DAG.getSetCC(DL, CCVT, N0, N1, ISD::SETEQ), DAG.getConstant(1, DL, VT), @@ -4463,6 +4457,15 @@ SDValue DAGCombiner::visitMULHS(SDNode *N) { EVT VT = N->getValueType(0); SDLoc DL(N); + // fold (mulhs c1, c2) + if (SDValue C = DAG.FoldConstantArithmetic(ISD::MULHS, DL, VT, {N0, N1})) + return C; + + // canonicalize constant to RHS. + if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && + !DAG.isConstantIntBuildVectorOrConstantInt(N1)) + return DAG.getNode(ISD::MULHS, DL, N->getVTList(), N1, N0); + if (VT.isVector()) { if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) return FoldedVOp; @@ -4474,15 +4477,6 @@ SDValue DAGCombiner::visitMULHS(SDNode *N) { return DAG.getConstant(0, DL, VT); } - // fold (mulhs c1, c2) - if (SDValue C = DAG.FoldConstantArithmetic(ISD::MULHS, DL, VT, {N0, N1})) - return C; - - // canonicalize constant to RHS. - if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && - !DAG.isConstantIntBuildVectorOrConstantInt(N1)) - return DAG.getNode(ISD::MULHS, DL, N->getVTList(), N1, N0); - // fold (mulhs x, 0) -> 0 if (isNullConstant(N1)) return N1; @@ -4523,6 +4517,15 @@ SDValue DAGCombiner::visitMULHU(SDNode *N) { EVT VT = N->getValueType(0); SDLoc DL(N); + // fold (mulhu c1, c2) + if (SDValue C = DAG.FoldConstantArithmetic(ISD::MULHU, DL, VT, {N0, N1})) + return C; + + // canonicalize constant to RHS. + if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && + !DAG.isConstantIntBuildVectorOrConstantInt(N1)) + return DAG.getNode(ISD::MULHU, DL, N->getVTList(), N1, N0); + if (VT.isVector()) { if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) return FoldedVOp; @@ -4534,15 +4537,6 @@ SDValue DAGCombiner::visitMULHU(SDNode *N) { return DAG.getConstant(0, DL, VT); } - // fold (mulhu c1, c2) - if (SDValue C = DAG.FoldConstantArithmetic(ISD::MULHU, DL, VT, {N0, N1})) - return C; - - // canonicalize constant to RHS. - if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && - !DAG.isConstantIntBuildVectorOrConstantInt(N1)) - return DAG.getNode(ISD::MULHU, DL, N->getVTList(), N1, N0); - // fold (mulhu x, 0) -> 0 if (isNullConstant(N1)) return N1; @@ -4786,12 +4780,14 @@ SDValue DAGCombiner::visitMULO(SDNode *N) { } // Function to calculate whether the Min/Max pair of SDNodes (potentially -// swapped around) make a signed saturate pattern, clamping to between -2^(BW-1) -// and 2^(BW-1)-1. Returns the node being clamped and the bitwidth of the clamp -// in BW. Should work with both SMIN/SMAX nodes and setcc/select combo. The -// operands are the same as SimplifySelectCC. N0getAPIntValue(); const APInt &MaxC = MaxCOp->getAPIntValue(); APInt MinCPlus1 = MinC + 1; - if (-MaxC != MinCPlus1 || !MinCPlus1.isPowerOf2()) - return SDValue(); - BW = MinCPlus1.exactLogBase2() + 1; - return N02; + if (-MaxC == MinCPlus1 && MinCPlus1.isPowerOf2()) { + BW = MinCPlus1.exactLogBase2() + 1; + Unsigned = false; + return N02; + } + + if (MaxC == 0 && MinCPlus1.isPowerOf2()) { + BW = MinCPlus1.exactLogBase2(); + Unsigned = true; + return N02; + } + + return SDValue(); } static SDValue PerformMinMaxFpToSatCombine(SDValue N0, SDValue N1, SDValue N2, SDValue N3, ISD::CondCode CC, SelectionDAG &DAG) { unsigned BW; - SDValue Fp = isSaturatingMinMax(N0, N1, N2, N3, CC, BW); + bool Unsigned; + SDValue Fp = isSaturatingMinMax(N0, N1, N2, N3, CC, BW, Unsigned); if (!Fp || Fp.getOpcode() != ISD::FP_TO_SINT) return SDValue(); EVT FPVT = Fp.getOperand(0).getValueType(); @@ -4876,13 +4882,14 @@ static SDValue PerformMinMaxFpToSatCombine(SDValue N0, SDValue N1, SDValue N2, if (FPVT.isVector()) NewVT = EVT::getVectorVT(*DAG.getContext(), NewVT, FPVT.getVectorElementCount()); - if (!DAG.getTargetLoweringInfo().shouldConvertFpToSat( - ISD::FP_TO_SINT_SAT, Fp.getOperand(0).getValueType(), NewVT)) + unsigned NewOpc = Unsigned ? ISD::FP_TO_UINT_SAT : ISD::FP_TO_SINT_SAT; + if (!DAG.getTargetLoweringInfo().shouldConvertFpToSat(NewOpc, FPVT, NewVT)) return SDValue(); SDLoc DL(Fp); - SDValue Sat = DAG.getNode(ISD::FP_TO_SINT_SAT, DL, NewVT, Fp.getOperand(0), + SDValue Sat = DAG.getNode(NewOpc, DL, NewVT, Fp.getOperand(0), DAG.getValueType(NewVT.getScalarType())); - return DAG.getSExtOrTrunc(Sat, DL, N2->getValueType(0)); + return Unsigned ? DAG.getZExtOrTrunc(Sat, DL, N2->getValueType(0)) + : DAG.getSExtOrTrunc(Sat, DL, N2->getValueType(0)); } SDValue DAGCombiner::visitIMINMAX(SDNode *N) { @@ -4892,11 +4899,6 @@ SDValue DAGCombiner::visitIMINMAX(SDNode *N) { unsigned Opcode = N->getOpcode(); SDLoc DL(N); - // fold vector ops - if (VT.isVector()) - if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) - return FoldedVOp; - // fold operation with constant operands. if (SDValue C = DAG.FoldConstantArithmetic(Opcode, DL, VT, {N0, N1})) return C; @@ -4904,7 +4906,12 @@ SDValue DAGCombiner::visitIMINMAX(SDNode *N) { // canonicalize constant to RHS if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && !DAG.isConstantIntBuildVectorOrConstantInt(N1)) - return DAG.getNode(N->getOpcode(), DL, VT, N1, N0); + return DAG.getNode(Opcode, DL, VT, N1, N0); + + // fold vector ops + if (VT.isVector()) + if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) + return FoldedVOp; // Is sign bits are zero, flip between UMIN/UMAX and SMIN/SMAX. // Only do this if the current op isn't legal and the flipped is. @@ -5777,6 +5784,15 @@ SDValue DAGCombiner::visitAND(SDNode *N) { if (N0 == N1) return N0; + // fold (and c1, c2) -> c1&c2 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::AND, SDLoc(N), VT, {N0, N1})) + return C; + + // canonicalize constant to RHS + if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && + !DAG.isConstantIntBuildVectorOrConstantInt(N1)) + return DAG.getNode(ISD::AND, SDLoc(N), VT, N1, N0); + // fold vector ops if (VT.isVector()) { if (SDValue FoldedVOp = SimplifyVBinOp(N, SDLoc(N))) @@ -5824,22 +5840,13 @@ SDValue DAGCombiner::visitAND(SDNode *N) { } } - // fold (and c1, c2) -> c1&c2 - ConstantSDNode *N1C = isConstOrConstSplat(N1); - if (SDValue C = DAG.FoldConstantArithmetic(ISD::AND, SDLoc(N), VT, {N0, N1})) - return C; - - // canonicalize constant to RHS - if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && - !DAG.isConstantIntBuildVectorOrConstantInt(N1)) - return DAG.getNode(ISD::AND, SDLoc(N), VT, N1, N0); - // fold (and x, -1) -> x if (isAllOnesConstant(N1)) return N0; // if (and x, c) is known to be zero, return 0 unsigned BitWidth = VT.getScalarSizeInBits(); + ConstantSDNode *N1C = isConstOrConstSplat(N1); if (N1C && DAG.MaskedValueIsZero(SDValue(N, 0), APInt::getAllOnes(BitWidth))) return DAG.getConstant(0, SDLoc(N), VT); @@ -6546,21 +6553,25 @@ SDValue DAGCombiner::visitOR(SDNode *N) { if (N0 == N1) return N0; + // fold (or c1, c2) -> c1|c2 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::OR, SDLoc(N), VT, {N0, N1})) + return C; + + // canonicalize constant to RHS + if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && + !DAG.isConstantIntBuildVectorOrConstantInt(N1)) + return DAG.getNode(ISD::OR, SDLoc(N), VT, N1, N0); + // fold vector ops if (VT.isVector()) { if (SDValue FoldedVOp = SimplifyVBinOp(N, SDLoc(N))) return FoldedVOp; // fold (or x, 0) -> x, vector edition - if (ISD::isConstantSplatVectorAllZeros(N0.getNode())) - return N1; if (ISD::isConstantSplatVectorAllZeros(N1.getNode())) return N0; // fold (or x, -1) -> -1, vector edition - if (ISD::isConstantSplatVectorAllOnes(N0.getNode())) - // do not return N0, because undef node may exist in N0 - return DAG.getAllOnesConstant(SDLoc(N), N0.getValueType()); if (ISD::isConstantSplatVectorAllOnes(N1.getNode())) // do not return N1, because undef node may exist in N1 return DAG.getAllOnesConstant(SDLoc(N), N1.getValueType()); @@ -6629,16 +6640,6 @@ SDValue DAGCombiner::visitOR(SDNode *N) { } } - // fold (or c1, c2) -> c1|c2 - ConstantSDNode *N1C = dyn_cast(N1); - if (SDValue C = DAG.FoldConstantArithmetic(ISD::OR, SDLoc(N), VT, {N0, N1})) - return C; - - // canonicalize constant to RHS - if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && - !DAG.isConstantIntBuildVectorOrConstantInt(N1)) - return DAG.getNode(ISD::OR, SDLoc(N), VT, N1, N0); - // fold (or x, 0) -> x if (isNullConstant(N1)) return N0; @@ -6651,6 +6652,7 @@ SDValue DAGCombiner::visitOR(SDNode *N) { return NewSel; // fold (or x, c) -> c iff (x & ~c) == 0 + ConstantSDNode *N1C = dyn_cast(N1); if (N1C && DAG.MaskedValueIsZero(N0, ~N1C->getAPIntValue())) return N1; @@ -7941,18 +7943,6 @@ SDValue DAGCombiner::visitXOR(SDNode *N) { EVT VT = N0.getValueType(); SDLoc DL(N); - // fold vector ops - if (VT.isVector()) { - if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) - return FoldedVOp; - - // fold (xor x, 0) -> x, vector edition - if (ISD::isConstantSplatVectorAllZeros(N0.getNode())) - return N1; - if (ISD::isConstantSplatVectorAllZeros(N1.getNode())) - return N0; - } - // fold (xor undef, undef) -> 0. This is a common idiom (misuse). if (N0.isUndef() && N1.isUndef()) return DAG.getConstant(0, DL, VT); @@ -7969,9 +7959,19 @@ SDValue DAGCombiner::visitXOR(SDNode *N) { // canonicalize constant to RHS if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && - !DAG.isConstantIntBuildVectorOrConstantInt(N1)) + !DAG.isConstantIntBuildVectorOrConstantInt(N1)) return DAG.getNode(ISD::XOR, DL, VT, N1, N0); + // fold vector ops + if (VT.isVector()) { + if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) + return FoldedVOp; + + // fold (xor x, 0) -> x, vector edition + if (ISD::isConstantSplatVectorAllZeros(N1.getNode())) + return N0; + } + // fold (xor x, 0) -> x if (isNullConstant(N1)) return N0; @@ -8409,6 +8409,10 @@ SDValue DAGCombiner::visitSHL(SDNode *N) { EVT ShiftVT = N1.getValueType(); unsigned OpSizeInBits = VT.getScalarSizeInBits(); + // fold (shl c1, c2) -> c1< c1< (shl X, (C2-C1)) if C1 <= C2 // fold (shl (sr[la] exact X, C1), C2) -> (sr[la] X, (C2-C1)) if C1 > C2 // TODO - support non-uniform vector shift amounts. + ConstantSDNode *N1C = isConstOrConstSplat(N1); if (N1C && (N0.getOpcode() == ISD::SRL || N0.getOpcode() == ISD::SRA) && N0->getFlags().hasExact()) { if (ConstantSDNode *N0C1 = isConstOrConstSplat(N0.getOperand(1))) { @@ -8758,6 +8757,10 @@ SDValue DAGCombiner::visitSRA(SDNode *N) { EVT VT = N0.getValueType(); unsigned OpSizeInBits = VT.getScalarSizeInBits(); + // fold (sra c1, c2) -> (sra c1, c2) + if (SDValue C = DAG.FoldConstantArithmetic(ISD::SRA, SDLoc(N), VT, {N0, N1})) + return C; + // Arithmetic shifting an all-sign-bit value is a no-op. // fold (sra 0, x) -> 0 // fold (sra -1, x) -> -1 @@ -8769,17 +8772,12 @@ SDValue DAGCombiner::visitSRA(SDNode *N) { if (SDValue FoldedVOp = SimplifyVBinOp(N, SDLoc(N))) return FoldedVOp; - ConstantSDNode *N1C = isConstOrConstSplat(N1); - - // fold (sra c1, c2) -> (sra c1, c2) - if (SDValue C = DAG.FoldConstantArithmetic(ISD::SRA, SDLoc(N), VT, {N0, N1})) - return C; - if (SDValue NewSel = foldBinOpIntoSelect(N)) return NewSel; // fold (sra (shl x, c1), c1) -> sext_inreg for some c1 and target supports // sext_inreg. + ConstantSDNode *N1C = isConstOrConstSplat(N1); if (N1C && N0.getOpcode() == ISD::SHL && N1 == N0.getOperand(1)) { unsigned LowBits = OpSizeInBits - (unsigned)N1C->getZExtValue(); EVT ExtVT = EVT::getIntegerVT(*DAG.getContext(), LowBits); @@ -8962,21 +8960,20 @@ SDValue DAGCombiner::visitSRL(SDNode *N) { EVT VT = N0.getValueType(); unsigned OpSizeInBits = VT.getScalarSizeInBits(); + // fold (srl c1, c2) -> c1 >>u c2 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::SRL, SDLoc(N), VT, {N0, N1})) + return C; + // fold vector ops if (VT.isVector()) if (SDValue FoldedVOp = SimplifyVBinOp(N, SDLoc(N))) return FoldedVOp; - ConstantSDNode *N1C = isConstOrConstSplat(N1); - - // fold (srl c1, c2) -> c1 >>u c2 - if (SDValue C = DAG.FoldConstantArithmetic(ISD::SRL, SDLoc(N), VT, {N0, N1})) - return C; - if (SDValue NewSel = foldBinOpIntoSelect(N)) return NewSel; // if (srl x, c) is known to be zero, return 0 + ConstantSDNode *N1C = isConstOrConstSplat(N1); if (N1C && DAG.MaskedValueIsZero(SDValue(N, 0), APInt::getAllOnes(OpSizeInBits))) return DAG.getConstant(0, SDLoc(N), VT); @@ -10043,6 +10040,8 @@ SDValue DAGCombiner::visitMSTORE(SDNode *N) { MaskedStoreSDNode *MST = cast(N); SDValue Mask = MST->getMask(); SDValue Chain = MST->getChain(); + SDValue Value = MST->getValue(); + SDValue Ptr = MST->getBasePtr(); SDLoc DL(N); // Zap masked stores with a zero mask. @@ -10054,12 +10053,50 @@ SDValue DAGCombiner::visitMSTORE(SDNode *N) { if (ISD::isConstantSplatVectorAllOnes(Mask.getNode()) && MST->isUnindexed() && !MST->isCompressingStore() && !MST->isTruncatingStore()) return DAG.getStore(MST->getChain(), SDLoc(N), MST->getValue(), - MST->getBasePtr(), MST->getMemOperand()); + MST->getBasePtr(), MST->getPointerInfo(), + MST->getOriginalAlign(), MachineMemOperand::MOStore, + MST->getAAInfo()); // Try transforming N to an indexed store. if (CombineToPreIndexedLoadStore(N) || CombineToPostIndexedLoadStore(N)) return SDValue(N, 0); + if (MST->isTruncatingStore() && MST->isUnindexed() && + Value.getValueType().isInteger() && + (!isa(Value) || + !cast(Value)->isOpaque())) { + APInt TruncDemandedBits = + APInt::getLowBitsSet(Value.getScalarValueSizeInBits(), + MST->getMemoryVT().getScalarSizeInBits()); + + // See if we can simplify the operation with + // SimplifyDemandedBits, which only works if the value has a single use. + if (SimplifyDemandedBits(Value, TruncDemandedBits)) { + // Re-visit the store if anything changed and the store hasn't been merged + // with another node (N is deleted) SimplifyDemandedBits will add Value's + // node back to the worklist if necessary, but we also need to re-visit + // the Store node itself. + if (N->getOpcode() != ISD::DELETED_NODE) + AddToWorklist(N); + return SDValue(N, 0); + } + } + + // If this is a TRUNC followed by a masked store, fold this into a masked + // truncating store. We can do this even if this is already a masked + // truncstore. + if ((Value.getOpcode() == ISD::TRUNCATE) && Value.getNode()->hasOneUse() && + MST->isUnindexed() && + TLI.canCombineTruncStore(Value.getOperand(0).getValueType(), + MST->getMemoryVT(), LegalOperations)) { + auto Mask = TLI.promoteTargetBoolean(DAG, MST->getMask(), + Value.getOperand(0).getValueType()); + return DAG.getMaskedStore(Chain, SDLoc(N), Value.getOperand(0), Ptr, + MST->getOffset(), Mask, MST->getMemoryVT(), + MST->getMemOperand(), MST->getAddressingMode(), + /*IsTruncating=*/true); + } + return SDValue(); } @@ -10109,8 +10146,10 @@ SDValue DAGCombiner::visitMLOAD(SDNode *N) { // FIXME: Can we do this for indexed, expanding, or extending loads? if (ISD::isConstantSplatVectorAllOnes(Mask.getNode()) && MLD->isUnindexed() && !MLD->isExpandingLoad() && MLD->getExtensionType() == ISD::NON_EXTLOAD) { - SDValue NewLd = DAG.getLoad(N->getValueType(0), SDLoc(N), MLD->getChain(), - MLD->getBasePtr(), MLD->getMemOperand()); + SDValue NewLd = DAG.getLoad( + N->getValueType(0), SDLoc(N), MLD->getChain(), MLD->getBasePtr(), + MLD->getPointerInfo(), MLD->getOriginalAlign(), + MachineMemOperand::MOLoad, MLD->getAAInfo(), MLD->getRanges()); return CombineTo(N, NewLd, NewLd.getValue(1)); } @@ -13876,19 +13915,19 @@ SDValue DAGCombiner::visitFADD(SDNode *N) { if (SDValue R = DAG.simplifyFPBinop(N->getOpcode(), N0, N1, Flags)) return R; - // fold vector ops - if (VT.isVector()) - if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) - return FoldedVOp; - // fold (fadd c1, c2) -> c1 + c2 - if (N0CFP && N1CFP) - return DAG.getNode(ISD::FADD, DL, VT, N0, N1); + if (SDValue C = DAG.FoldConstantArithmetic(ISD::FADD, DL, VT, {N0, N1})) + return C; // canonicalize constant to RHS if (N0CFP && !N1CFP) return DAG.getNode(ISD::FADD, DL, VT, N1, N0); + // fold vector ops + if (VT.isVector()) + if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) + return FoldedVOp; + // N0 + -0.0 --> N0 (also allowed with +0.0 and fast-math) ConstantFPSDNode *N1C = isConstOrConstSplatFP(N1, true); if (N1C && N1C->isZero()) @@ -14084,15 +14123,15 @@ SDValue DAGCombiner::visitFSUB(SDNode *N) { if (SDValue R = DAG.simplifyFPBinop(N->getOpcode(), N0, N1, Flags)) return R; + // fold (fsub c1, c2) -> c1-c2 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::FSUB, DL, VT, {N0, N1})) + return C; + // fold vector ops if (VT.isVector()) if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) return FoldedVOp; - // fold (fsub c1, c2) -> c1-c2 - if (N0CFP && N1CFP) - return DAG.getNode(ISD::FSUB, DL, VT, N0, N1); - if (SDValue NewSel = foldBinOpIntoSelect(N)) return NewSel; @@ -14157,7 +14196,6 @@ SDValue DAGCombiner::visitFSUB(SDNode *N) { SDValue DAGCombiner::visitFMUL(SDNode *N) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); - ConstantFPSDNode *N0CFP = isConstOrConstSplatFP(N0, true); ConstantFPSDNode *N1CFP = isConstOrConstSplatFP(N1, true); EVT VT = N->getValueType(0); SDLoc DL(N); @@ -14168,22 +14206,20 @@ SDValue DAGCombiner::visitFMUL(SDNode *N) { if (SDValue R = DAG.simplifyFPBinop(N->getOpcode(), N0, N1, Flags)) return R; - // fold vector ops - if (VT.isVector()) { - // This just handles C1 * C2 for vectors. Other vector folds are below. - if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) - return FoldedVOp; - } - // fold (fmul c1, c2) -> c1*c2 - if (N0CFP && N1CFP) - return DAG.getNode(ISD::FMUL, DL, VT, N0, N1); + if (SDValue C = DAG.FoldConstantArithmetic(ISD::FMUL, DL, VT, {N0, N1})) + return C; // canonicalize constant to RHS if (DAG.isConstantFPBuildVectorOrConstantFP(N0) && !DAG.isConstantFPBuildVectorOrConstantFP(N1)) return DAG.getNode(ISD::FMUL, DL, VT, N1, N0); + // fold vector ops + if (VT.isVector()) + if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) + return FoldedVOp; + if (SDValue NewSel = foldBinOpIntoSelect(N)) return NewSel; @@ -14495,8 +14531,6 @@ SDValue DAGCombiner::combineRepeatedFPDivisors(SDNode *N) { SDValue DAGCombiner::visitFDIV(SDNode *N) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); - ConstantFPSDNode *N0CFP = dyn_cast(N0); - ConstantFPSDNode *N1CFP = dyn_cast(N1); EVT VT = N->getValueType(0); SDLoc DL(N); const TargetOptions &Options = DAG.getTarget().Options; @@ -14506,15 +14540,15 @@ SDValue DAGCombiner::visitFDIV(SDNode *N) { if (SDValue R = DAG.simplifyFPBinop(N->getOpcode(), N0, N1, Flags)) return R; + // fold (fdiv c1, c2) -> c1/c2 + if (SDValue C = DAG.FoldConstantArithmetic(ISD::FDIV, DL, VT, {N0, N1})) + return C; + // fold vector ops if (VT.isVector()) if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) return FoldedVOp; - // fold (fdiv c1, c2) -> c1/c2 - if (N0CFP && N1CFP) - return DAG.getNode(ISD::FDIV, SDLoc(N), VT, N0, N1); - if (SDValue NewSel = foldBinOpIntoSelect(N)) return NewSel; @@ -14523,7 +14557,7 @@ SDValue DAGCombiner::visitFDIV(SDNode *N) { if (Options.UnsafeFPMath || Flags.hasAllowReciprocal()) { // fold (fdiv X, c2) -> fmul X, 1/c2 if losing precision is acceptable. - if (N1CFP) { + if (auto *N1CFP = dyn_cast(N1)) { // Compute the reciprocal 1.0 / c2. const APFloat &N1APF = N1CFP->getValueAPF(); APFloat Recip(N1APF.getSemantics(), 1); // 1.0 @@ -14639,8 +14673,6 @@ SDValue DAGCombiner::visitFDIV(SDNode *N) { SDValue DAGCombiner::visitFREM(SDNode *N) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); - ConstantFPSDNode *N0CFP = dyn_cast(N0); - ConstantFPSDNode *N1CFP = dyn_cast(N1); EVT VT = N->getValueType(0); SDNodeFlags Flags = N->getFlags(); SelectionDAG::FlagInserter FlagsInserter(DAG, N); @@ -14649,9 +14681,9 @@ SDValue DAGCombiner::visitFREM(SDNode *N) { return R; // fold (frem c1, c2) -> fmod(c1,c2) - if (N0CFP && N1CFP) - return DAG.getNode(ISD::FREM, SDLoc(N), VT, N0, N1); - + if (SDValue C = DAG.FoldConstantArithmetic(ISD::FREM, SDLoc(N), VT, {N0, N1})) + return C; + if (SDValue NewSel = foldBinOpIntoSelect(N)) return NewSel; @@ -14712,12 +14744,12 @@ static inline bool CanCombineFCOPYSIGN_EXTEND_ROUND(SDNode *N) { SDValue DAGCombiner::visitFCOPYSIGN(SDNode *N) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); - bool N0CFP = DAG.isConstantFPBuildVectorOrConstantFP(N0); - bool N1CFP = DAG.isConstantFPBuildVectorOrConstantFP(N1); EVT VT = N->getValueType(0); - if (N0CFP && N1CFP) // Constant fold - return DAG.getNode(ISD::FCOPYSIGN, SDLoc(N), VT, N0, N1); + // fold (fcopysign c1, c2) -> fcopysign(c1,c2) + if (SDValue C = + DAG.FoldConstantArithmetic(ISD::FCOPYSIGN, SDLoc(N), VT, {N0, N1})) + return C; if (ConstantFPSDNode *N1C = isConstOrConstSplatFP(N->getOperand(1))) { const APFloat &V = N1C->getValueAPF(); @@ -14835,14 +14867,6 @@ SDValue DAGCombiner::visitFPOW(SDNode *N) { static SDValue foldFPToIntToFP(SDNode *N, SelectionDAG &DAG, const TargetLowering &TLI) { - // This optimization is guarded by a function attribute because it may produce - // unexpected results. Ie, programs may be relying on the platform-specific - // undefined behavior when the float-to-int conversion overflows. - const Function &F = DAG.getMachineFunction().getFunction(); - Attribute StrictOverflow = F.getFnAttribute("strict-float-cast-overflow"); - if (StrictOverflow.getValueAsString().equals("false")) - return SDValue(); - // We only do this if the target has legal ftrunc. Otherwise, we'd likely be // replacing casts with a libcall. We also must be allowed to ignore -0.0 // because FTRUNC will return -0.0 for (-1.0, -0.0), but using integer @@ -15216,31 +15240,26 @@ SDValue DAGCombiner::visitFNEG(SDNode *N) { return SDValue(); } -static SDValue visitFMinMax(SelectionDAG &DAG, SDNode *N, - APFloat (*Op)(const APFloat &, const APFloat &)) { +SDValue DAGCombiner::visitFMinMax(SDNode *N) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); EVT VT = N->getValueType(0); - const ConstantFPSDNode *N0CFP = isConstOrConstSplatFP(N0); - const ConstantFPSDNode *N1CFP = isConstOrConstSplatFP(N1); const SDNodeFlags Flags = N->getFlags(); unsigned Opc = N->getOpcode(); bool PropagatesNaN = Opc == ISD::FMINIMUM || Opc == ISD::FMAXIMUM; bool IsMin = Opc == ISD::FMINNUM || Opc == ISD::FMINIMUM; SelectionDAG::FlagInserter FlagsInserter(DAG, N); - if (N0CFP && N1CFP) { - const APFloat &C0 = N0CFP->getValueAPF(); - const APFloat &C1 = N1CFP->getValueAPF(); - return DAG.getConstantFP(Op(C0, C1), SDLoc(N), VT); - } + // Constant fold. + if (SDValue C = DAG.FoldConstantArithmetic(Opc, SDLoc(N), VT, {N0, N1})) + return C; // Canonicalize to constant on RHS. if (DAG.isConstantFPBuildVectorOrConstantFP(N0) && !DAG.isConstantFPBuildVectorOrConstantFP(N1)) return DAG.getNode(N->getOpcode(), SDLoc(N), VT, N1, N0); - if (N1CFP) { + if (const ConstantFPSDNode *N1CFP = isConstOrConstSplatFP(N1)) { const APFloat &AF = N1CFP->getValueAPF(); // minnum(X, nan) -> X @@ -15272,22 +15291,6 @@ static SDValue visitFMinMax(SelectionDAG &DAG, SDNode *N, return SDValue(); } -SDValue DAGCombiner::visitFMINNUM(SDNode *N) { - return visitFMinMax(DAG, N, minnum); -} - -SDValue DAGCombiner::visitFMAXNUM(SDNode *N) { - return visitFMinMax(DAG, N, maxnum); -} - -SDValue DAGCombiner::visitFMINIMUM(SDNode *N) { - return visitFMinMax(DAG, N, minimum); -} - -SDValue DAGCombiner::visitFMAXIMUM(SDNode *N) { - return visitFMinMax(DAG, N, maximum); -} - SDValue DAGCombiner::visitFABS(SDNode *N) { SDValue N0 = N->getOperand(0); EVT VT = N->getValueType(0); @@ -18392,8 +18395,8 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { if (StoreSDNode *ST1 = dyn_cast(Chain)) { if (ST->isUnindexed() && ST->isSimple() && ST1->isUnindexed() && ST1->isSimple()) { - if (ST1->getBasePtr() == Ptr && ST1->getValue() == Value && - ST->getMemoryVT() == ST1->getMemoryVT() && + if (OptLevel != CodeGenOpt::None && ST1->getBasePtr() == Ptr && + ST1->getValue() == Value && ST->getMemoryVT() == ST1->getMemoryVT() && ST->getAddressSpace() == ST1->getAddressSpace()) { // If this is a store followed by a store with the same value to the // same location, then the store is dead/noop. @@ -20727,6 +20730,156 @@ static SDValue narrowExtractedVectorLoad(SDNode *Extract, SelectionDAG &DAG) { return NewLd; } +/// Given EXTRACT_SUBVECTOR(VECTOR_SHUFFLE(Op0, Op1, Mask)), +/// try to produce VECTOR_SHUFFLE(EXTRACT_SUBVECTOR(Op?, ?), +/// EXTRACT_SUBVECTOR(Op?, ?), +/// Mask')) +/// iff it is legal and profitable to do so. Notably, the trimmed mask +/// (containing only the elements that are extracted) +/// must reference at most two subvectors. +static SDValue foldExtractSubvectorFromShuffleVector(SDNode *N, + SelectionDAG &DAG, + const TargetLowering &TLI, + bool LegalOperations) { + assert(N->getOpcode() == ISD::EXTRACT_SUBVECTOR && + "Must only be called on EXTRACT_SUBVECTOR's"); + + SDValue N0 = N->getOperand(0); + + // Only deal with non-scalable vectors. + EVT NarrowVT = N->getValueType(0); + EVT WideVT = N0.getValueType(); + if (!NarrowVT.isFixedLengthVector() || !WideVT.isFixedLengthVector()) + return SDValue(); + + // The operand must be a shufflevector. + auto *WideShuffleVector = dyn_cast(N0); + if (!WideShuffleVector) + return SDValue(); + + // The old shuffleneeds to go away. + if (!WideShuffleVector->hasOneUse()) + return SDValue(); + + // And the narrow shufflevector that we'll form must be legal. + if (LegalOperations && + !TLI.isOperationLegalOrCustom(ISD::VECTOR_SHUFFLE, NarrowVT)) + return SDValue(); + + uint64_t FirstExtractedEltIdx = N->getConstantOperandVal(1); + int NumEltsExtracted = NarrowVT.getVectorNumElements(); + assert((FirstExtractedEltIdx % NumEltsExtracted) == 0 && + "Extract index is not a multiple of the output vector length."); + + int WideNumElts = WideVT.getVectorNumElements(); + + SmallVector NewMask; + NewMask.reserve(NumEltsExtracted); + SmallSetVector, 2> + DemandedSubvectors; + + // Try to decode the wide mask into narrow mask from at most two subvectors. + for (int M : WideShuffleVector->getMask().slice(FirstExtractedEltIdx, + NumEltsExtracted)) { + assert((M >= -1) && (M < (2 * WideNumElts)) && + "Out-of-bounds shuffle mask?"); + + if (M < 0) { + // Does not depend on operands, does not require adjustment. + NewMask.emplace_back(M); + continue; + } + + // From which operand of the shuffle does this shuffle mask element pick? + int WideShufOpIdx = M / WideNumElts; + // Which element of that operand is picked? + int OpEltIdx = M % WideNumElts; + + assert((OpEltIdx + WideShufOpIdx * WideNumElts) == M && + "Shuffle mask vector decomposition failure."); + + // And which NumEltsExtracted-sized subvector of that operand is that? + int OpSubvecIdx = OpEltIdx / NumEltsExtracted; + // And which element within that subvector of that operand is that? + int OpEltIdxInSubvec = OpEltIdx % NumEltsExtracted; + + assert((OpEltIdxInSubvec + OpSubvecIdx * NumEltsExtracted) == OpEltIdx && + "Shuffle mask subvector decomposition failure."); + + assert((OpEltIdxInSubvec + OpSubvecIdx * NumEltsExtracted + + WideShufOpIdx * WideNumElts) == M && + "Shuffle mask full decomposition failure."); + + SDValue Op = WideShuffleVector->getOperand(WideShufOpIdx); + + if (Op.isUndef()) { + // Picking from an undef operand. Let's adjust mask instead. + NewMask.emplace_back(-1); + continue; + } + + // Profitability check: only deal with extractions from the first subvector. + if (OpSubvecIdx != 0) + return SDValue(); + + const std::pair DemandedSubvector = + std::make_pair(Op, OpSubvecIdx); + + if (DemandedSubvectors.insert(DemandedSubvector)) { + if (DemandedSubvectors.size() > 2) + return SDValue(); // We can't handle more than two subvectors. + // How many elements into the WideVT does this subvector start? + int Index = NumEltsExtracted * OpSubvecIdx; + // Bail out if the extraction isn't going to be cheap. + if (!TLI.isExtractSubvectorCheap(NarrowVT, WideVT, Index)) + return SDValue(); + } + + // Ok, but from which operand of the new shuffle will this element pick? + int NewOpIdx = + getFirstIndexOf(DemandedSubvectors.getArrayRef(), DemandedSubvector); + assert((NewOpIdx == 0 || NewOpIdx == 1) && "Unexpected operand index."); + + int AdjM = OpEltIdxInSubvec + NewOpIdx * NumEltsExtracted; + NewMask.emplace_back(AdjM); + } + assert(NewMask.size() == (unsigned)NumEltsExtracted && "Produced bad mask."); + assert(DemandedSubvectors.size() <= 2 && + "Should have ended up demanding at most two subvectors."); + + // Did we discover that the shuffle does not actually depend on operands? + if (DemandedSubvectors.empty()) + return DAG.getUNDEF(NarrowVT); + + // We still perform the exact same EXTRACT_SUBVECTOR, just on different + // operand[s]/index[es], so there is no point in checking for it's legality. + + // Do not turn a legal shuffle into an illegal one. + if (TLI.isShuffleMaskLegal(WideShuffleVector->getMask(), WideVT) && + !TLI.isShuffleMaskLegal(NewMask, NarrowVT)) + return SDValue(); + + SDLoc DL(N); + + SmallVector NewOps; + for (const std::pair + &DemandedSubvector : DemandedSubvectors) { + // How many elements into the WideVT does this subvector start? + int Index = NumEltsExtracted * DemandedSubvector.second; + SDValue IndexC = DAG.getVectorIdxConstant(Index, DL); + NewOps.emplace_back(DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, NarrowVT, + DemandedSubvector.first, IndexC)); + } + assert((NewOps.size() == 1 || NewOps.size() == 2) && + "Should end up with either one or two ops"); + + // If we ended up with only one operand, pad with an undef. + if (NewOps.size() == 1) + NewOps.emplace_back(DAG.getUNDEF(NarrowVT)); + + return DAG.getVectorShuffle(NarrowVT, DL, NewOps[0], NewOps[1], NewMask); +} + SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) { EVT NVT = N->getValueType(0); SDValue V = N->getOperand(0); @@ -20840,6 +20993,10 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) { } } + if (SDValue V = + foldExtractSubvectorFromShuffleVector(N, DAG, TLI, LegalOperations)) + return V; + V = peekThroughBitcasts(V); // If the input is a build vector. Try to make a smaller build vector. @@ -22424,15 +22581,9 @@ SDValue DAGCombiner::SimplifyVBinOp(SDNode *N, const SDLoc &DL) { SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); - SDValue Ops[] = {LHS, RHS}; unsigned Opcode = N->getOpcode(); SDNodeFlags Flags = N->getFlags(); - // See if we can constant fold the vector operation. - if (SDValue Fold = DAG.FoldConstantArithmetic(Opcode, SDLoc(LHS), - LHS.getValueType(), Ops)) - return Fold; - // Move unary shuffles with identical masks after a vector binop: // VBinOp (shuffle A, Undef, Mask), (shuffle B, Undef, Mask)) // --> shuffle (VBinOp A, B), Undef, Mask diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 08598eeded7a..5dfb65ef131a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -3367,13 +3367,13 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) { } case ISD::FSHL: case ISD::FSHR: - if (TLI.expandFunnelShift(Node, Tmp1, DAG)) - Results.push_back(Tmp1); + if (SDValue Expanded = TLI.expandFunnelShift(Node, DAG)) + Results.push_back(Expanded); break; case ISD::ROTL: case ISD::ROTR: - if (TLI.expandROT(Node, true /*AllowVectorOps*/, Tmp1, DAG)) - Results.push_back(Tmp1); + if (SDValue Expanded = TLI.expandROT(Node, true /*AllowVectorOps*/, DAG)) + Results.push_back(Expanded); break; case ISD::SADDSAT: case ISD::UADDSAT: diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index 1fa4d88fcb4a..518e525e13d0 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -1277,8 +1277,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_SRL(SDNode *N, bool IsVP) { SDValue DAGTypeLegalizer::PromoteIntRes_Rotate(SDNode *N) { // Lower the rotate to shifts and ORs which can be promoted. - SDValue Res; - TLI.expandROT(N, true /*AllowVectorOps*/, Res, DAG); + SDValue Res = TLI.expandROT(N, true /*AllowVectorOps*/, DAG); ReplaceValueWith(SDValue(N, 0), Res); return SDValue(); } @@ -1286,7 +1285,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Rotate(SDNode *N) { SDValue DAGTypeLegalizer::PromoteIntRes_FunnelShift(SDNode *N) { SDValue Hi = GetPromotedInteger(N->getOperand(0)); SDValue Lo = GetPromotedInteger(N->getOperand(1)); - SDValue Amount = GetPromotedInteger(N->getOperand(2)); + SDValue Amt = GetPromotedInteger(N->getOperand(2)); SDLoc DL(N); EVT OldVT = N->getOperand(0).getValueType(); @@ -1297,21 +1296,20 @@ SDValue DAGTypeLegalizer::PromoteIntRes_FunnelShift(SDNode *N) { unsigned NewBits = VT.getScalarSizeInBits(); // Amount has to be interpreted modulo the old bit width. - Amount = - DAG.getNode(ISD::UREM, DL, VT, Amount, DAG.getConstant(OldBits, DL, VT)); + Amt = DAG.getNode(ISD::UREM, DL, VT, Amt, DAG.getConstant(OldBits, DL, VT)); // If the promoted type is twice the size (or more), then we use the // traditional funnel 'double' shift codegen. This isn't necessary if the // shift amount is constant. // fshl(x,y,z) -> (((aext(x) << bw) | zext(y)) << (z % bw)) >> bw. // fshr(x,y,z) -> (((aext(x) << bw) | zext(y)) >> (z % bw)). - if (NewBits >= (2 * OldBits) && !isa(Amount) && + if (NewBits >= (2 * OldBits) && !isa(Amt) && !TLI.isOperationLegalOrCustom(Opcode, VT)) { SDValue HiShift = DAG.getConstant(OldBits, DL, VT); Hi = DAG.getNode(ISD::SHL, DL, VT, Hi, HiShift); Lo = DAG.getZeroExtendInReg(Lo, DL, OldVT); SDValue Res = DAG.getNode(ISD::OR, DL, VT, Hi, Lo); - Res = DAG.getNode(IsFSHR ? ISD::SRL : ISD::SHL, DL, VT, Res, Amount); + Res = DAG.getNode(IsFSHR ? ISD::SRL : ISD::SHL, DL, VT, Res, Amt); if (!IsFSHR) Res = DAG.getNode(ISD::SRL, DL, VT, Res, HiShift); return Res; @@ -1324,9 +1322,9 @@ SDValue DAGTypeLegalizer::PromoteIntRes_FunnelShift(SDNode *N) { // Increase Amount to shift the result into the lower bits of the promoted // type. if (IsFSHR) - Amount = DAG.getNode(ISD::ADD, DL, VT, Amount, ShiftOffset); + Amt = DAG.getNode(ISD::ADD, DL, VT, Amt, ShiftOffset); - return DAG.getNode(Opcode, DL, VT, Hi, Lo, Amount); + return DAG.getNode(Opcode, DL, VT, Hi, Lo, Amt); } SDValue DAGTypeLegalizer::PromoteIntRes_TRUNCATE(SDNode *N) { diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp index 98312f91d8c0..03dcd0f6d2c9 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp @@ -83,7 +83,7 @@ void DAGTypeLegalizer::PerformExpensiveChecks() { SDValue Res(&Node, i); bool Failed = false; // Don't create a value in map. - auto ResId = (ValueToIdMap.count(Res)) ? ValueToIdMap[Res] : 0; + auto ResId = ValueToIdMap.lookup(Res); unsigned Mapped = 0; if (ResId && (ReplacedValues.find(ResId) != ReplacedValues.end())) { @@ -301,7 +301,7 @@ ScanOperands: if (IgnoreNodeResults(N->getOperand(i).getNode())) continue; - const auto Op = N->getOperand(i); + const auto &Op = N->getOperand(i); LLVM_DEBUG(dbgs() << "Analyzing operand: "; Op.dump(&DAG)); EVT OpVT = Op.getValueType(); switch (getTypeAction(OpVT)) { @@ -1007,11 +1007,7 @@ SDValue DAGTypeLegalizer::JoinIntegers(SDValue Lo, SDValue Hi) { /// /// ValVT is the type of values that produced the boolean. SDValue DAGTypeLegalizer::PromoteTargetBoolean(SDValue Bool, EVT ValVT) { - SDLoc dl(Bool); - EVT BoolVT = getSetCCResultType(ValVT); - ISD::NodeType ExtendCode = - TargetLowering::getExtendForContent(TLI.getBooleanContents(ValVT)); - return DAG.getNode(ExtendCode, dl, BoolVT, Bool); + return TLI.promoteTargetBoolean(DAG, Bool, ValVT); } /// Return the lower LoVT bits of Op in Lo and the upper HiVT bits in Hi. diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp index 88a28a3be53e..1493f36fcd3e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp @@ -254,69 +254,6 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { SDNode *Node = DAG.UpdateNodeOperands(Op.getNode(), Ops); - if (Op.getOpcode() == ISD::LOAD) { - LoadSDNode *LD = cast(Node); - ISD::LoadExtType ExtType = LD->getExtensionType(); - if (LD->getMemoryVT().isVector() && ExtType != ISD::NON_EXTLOAD) { - LLVM_DEBUG(dbgs() << "\nLegalizing extending vector load: "; - Node->dump(&DAG)); - switch (TLI.getLoadExtAction(LD->getExtensionType(), LD->getValueType(0), - LD->getMemoryVT())) { - default: llvm_unreachable("This action is not supported yet!"); - case TargetLowering::Legal: - return TranslateLegalizeResults(Op, Node); - case TargetLowering::Custom: { - SmallVector ResultVals; - if (LowerOperationWrapper(Node, ResultVals)) { - if (ResultVals.empty()) - return TranslateLegalizeResults(Op, Node); - - Changed = true; - return RecursivelyLegalizeResults(Op, ResultVals); - } - LLVM_FALLTHROUGH; - } - case TargetLowering::Expand: { - Changed = true; - std::pair Tmp = ExpandLoad(Node); - AddLegalizedOperand(Op.getValue(0), Tmp.first); - AddLegalizedOperand(Op.getValue(1), Tmp.second); - return Op.getResNo() ? Tmp.first : Tmp.second; - } - } - } - } else if (Op.getOpcode() == ISD::STORE) { - StoreSDNode *ST = cast(Node); - EVT StVT = ST->getMemoryVT(); - MVT ValVT = ST->getValue().getSimpleValueType(); - if (StVT.isVector() && ST->isTruncatingStore()) { - LLVM_DEBUG(dbgs() << "\nLegalizing truncating vector store: "; - Node->dump(&DAG)); - switch (TLI.getTruncStoreAction(ValVT, StVT)) { - default: llvm_unreachable("This action is not supported yet!"); - case TargetLowering::Legal: - return TranslateLegalizeResults(Op, Node); - case TargetLowering::Custom: { - SmallVector ResultVals; - if (LowerOperationWrapper(Node, ResultVals)) { - if (ResultVals.empty()) - return TranslateLegalizeResults(Op, Node); - - Changed = true; - return RecursivelyLegalizeResults(Op, ResultVals); - } - LLVM_FALLTHROUGH; - } - case TargetLowering::Expand: { - Changed = true; - SDValue Chain = ExpandStore(Node); - AddLegalizedOperand(Op, Chain); - return Chain; - } - } - } - } - bool HasVectorValueOrOp = llvm::any_of(Node->values(), [](EVT T) { return T.isVector(); }) || llvm::any_of(Node->op_values(), @@ -329,6 +266,22 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { switch (Op.getOpcode()) { default: return TranslateLegalizeResults(Op, Node); + case ISD::LOAD: { + LoadSDNode *LD = cast(Node); + ISD::LoadExtType ExtType = LD->getExtensionType(); + EVT LoadedVT = LD->getMemoryVT(); + if (LoadedVT.isVector() && ExtType != ISD::NON_EXTLOAD) + Action = TLI.getLoadExtAction(ExtType, LD->getValueType(0), LoadedVT); + break; + } + case ISD::STORE: { + StoreSDNode *ST = cast(Node); + EVT StVT = ST->getMemoryVT(); + MVT ValVT = ST->getValue().getSimpleValueType(); + if (StVT.isVector() && ST->isTruncatingStore()) + Action = TLI.getTruncStoreAction(ValVT, StVT); + break; + } case ISD::MERGE_VALUES: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); // This operation lies about being legal: when it claims to be legal, @@ -512,6 +465,8 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { switch (Action) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Promote: + assert((Op.getOpcode() != ISD::LOAD && Op.getOpcode() != ISD::STORE) && + "This action is not supported yet!"); LLVM_DEBUG(dbgs() << "Promoting\n"); Promote(Node, ResultVals); assert(!ResultVals.empty() && "No results for promotion?"); @@ -731,8 +686,16 @@ SDValue VectorLegalizer::ExpandStore(SDNode *N) { } void VectorLegalizer::Expand(SDNode *Node, SmallVectorImpl &Results) { - SDValue Tmp; switch (Node->getOpcode()) { + case ISD::LOAD: { + std::pair Tmp = ExpandLoad(Node); + Results.push_back(Tmp.first); + Results.push_back(Tmp.second); + return; + } + case ISD::STORE: + Results.push_back(ExpandStore(Node)); + return; case ISD::MERGE_VALUES: for (unsigned i = 0, e = Node->getNumValues(); i != e; ++i) Results.push_back(Node->getOperand(i)); @@ -804,15 +767,15 @@ void VectorLegalizer::Expand(SDNode *Node, SmallVectorImpl &Results) { break; case ISD::FSHL: case ISD::FSHR: - if (TLI.expandFunnelShift(Node, Tmp, DAG)) { - Results.push_back(Tmp); + if (SDValue Expanded = TLI.expandFunnelShift(Node, DAG)) { + Results.push_back(Expanded); return; } break; case ISD::ROTL: case ISD::ROTR: - if (TLI.expandROT(Node, false /*AllowVectorOps*/, Tmp, DAG)) { - Results.push_back(Tmp); + if (SDValue Expanded = TLI.expandROT(Node, false /*AllowVectorOps*/, DAG)) { + Results.push_back(Expanded); return; } break; diff --git a/llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp b/llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp index 2695ed36991c..3d5c4c5b1cae 100644 --- a/llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp @@ -168,10 +168,9 @@ void ResourcePriorityQueue::initNodes(std::vector &sunits) { SUnits = &sunits; NumNodesSolelyBlocking.resize(SUnits->size(), 0); - for (unsigned i = 0, e = SUnits->size(); i != e; ++i) { - SUnit *SU = &(*SUnits)[i]; - initNumRegDefsLeft(SU); - SU->NodeQueueId = 0; + for (SUnit &SU : *SUnits) { + initNumRegDefsLeft(&SU); + SU.NodeQueueId = 0; } } diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp index 84e6d2a16422..aec2cf38b400 100644 --- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -442,33 +442,32 @@ void ScheduleDAGSDNodes::AddSchedEdges() { bool UnitLatencies = forceUnitLatencies(); // Pass 2: add the preds, succs, etc. - for (unsigned su = 0, e = SUnits.size(); su != e; ++su) { - SUnit *SU = &SUnits[su]; - SDNode *MainNode = SU->getNode(); + for (SUnit &SU : SUnits) { + SDNode *MainNode = SU.getNode(); if (MainNode->isMachineOpcode()) { unsigned Opc = MainNode->getMachineOpcode(); const MCInstrDesc &MCID = TII->get(Opc); for (unsigned i = 0; i != MCID.getNumOperands(); ++i) { if (MCID.getOperandConstraint(i, MCOI::TIED_TO) != -1) { - SU->isTwoAddress = true; + SU.isTwoAddress = true; break; } } if (MCID.isCommutable()) - SU->isCommutable = true; + SU.isCommutable = true; } // Find all predecessors and successors of the group. - for (SDNode *N = SU->getNode(); N; N = N->getGluedNode()) { + for (SDNode *N = SU.getNode(); N; N = N->getGluedNode()) { if (N->isMachineOpcode() && TII->get(N->getMachineOpcode()).getImplicitDefs()) { - SU->hasPhysRegClobbers = true; + SU.hasPhysRegClobbers = true; unsigned NumUsed = InstrEmitter::CountResults(N); while (NumUsed != 0 && !N->hasAnyUseOfValue(NumUsed - 1)) --NumUsed; // Skip over unused values at the end. if (NumUsed > TII->get(N->getMachineOpcode()).getNumDefs()) - SU->hasPhysRegDefs = true; + SU.hasPhysRegDefs = true; } for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { @@ -477,7 +476,8 @@ void ScheduleDAGSDNodes::AddSchedEdges() { if (isPassiveNode(OpN)) continue; // Not scheduled. SUnit *OpSU = &SUnits[OpN->getNodeId()]; assert(OpSU && "Node has no SUnit!"); - if (OpSU == SU) continue; // In the same group. + if (OpSU == &SU) + continue; // In the same group. EVT OpVT = N->getOperand(i).getValueType(); assert(OpVT != MVT::Glue && "Glued nodes should be in same sunit!"); @@ -508,10 +508,10 @@ void ScheduleDAGSDNodes::AddSchedEdges() { Dep.setLatency(OpLatency); if (!isChain && !UnitLatencies) { computeOperandLatency(OpN, N, i, Dep); - ST.adjustSchedDependency(OpSU, DefIdx, SU, i, Dep); + ST.adjustSchedDependency(OpSU, DefIdx, &SU, i, Dep); } - if (!SU->addPred(Dep) && !Dep.isCtrl() && OpSU->NumRegDefsLeft > 1) { + if (!SU.addPred(Dep) && !Dep.isCtrl() && OpSU->NumRegDefsLeft > 1) { // Multiple register uses are combined in the same SUnit. For example, // we could have a set of glued nodes with all their defs consumed by // another set of glued nodes. Register pressure tracking sees this as @@ -721,10 +721,7 @@ void ScheduleDAGSDNodes::dumpSchedule() const { /// void ScheduleDAGSDNodes::VerifyScheduledSequence(bool isBottomUp) { unsigned ScheduledNodes = ScheduleDAG::VerifyScheduledDAG(isBottomUp); - unsigned Noops = 0; - for (unsigned i = 0, e = Sequence.size(); i != e; ++i) - if (!Sequence[i]) - ++Noops; + unsigned Noops = llvm::count(Sequence, nullptr); assert(Sequence.size() - Noops == ScheduledNodes && "The number of nodes scheduled doesn't match the expected number!"); } @@ -911,8 +908,7 @@ EmitSchedule(MachineBasicBlock::iterator &InsertPos) { } } - for (unsigned i = 0, e = Sequence.size(); i != e; i++) { - SUnit *SU = Sequence[i]; + for (SUnit *SU : Sequence) { if (!SU) { // Null SUnit* is a noop. TII->insertNoop(*Emitter.getBlock(), InsertPos); diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGVLIW.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGVLIW.cpp index 540a6e3efbe1..10940478010e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGVLIW.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGVLIW.cpp @@ -169,11 +169,11 @@ void ScheduleDAGVLIW::listScheduleTopDown() { releaseSuccessors(&EntrySU); // All leaves to AvailableQueue. - for (unsigned i = 0, e = SUnits.size(); i != e; ++i) { + for (SUnit &SU : SUnits) { // It is available if it has no predecessors. - if (SUnits[i].Preds.empty()) { - AvailableQueue->push(&SUnits[i]); - SUnits[i].isAvailable = true; + if (SU.Preds.empty()) { + AvailableQueue->push(&SU); + SU.isAvailable = true; } } diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index c282e03387dd..2ae0d4df7b77 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2499,7 +2499,8 @@ bool SelectionDAG::MaskedValueIsAllOnes(SDValue V, const APInt &Mask, /// sense to specify which elements are demanded or undefined, therefore /// they are simply ignored. bool SelectionDAG::isSplatValue(SDValue V, const APInt &DemandedElts, - APInt &UndefElts, unsigned Depth) { + APInt &UndefElts, unsigned Depth) const { + unsigned Opcode = V.getOpcode(); EVT VT = V.getValueType(); assert(VT.isVector() && "Vector type expected"); @@ -2511,7 +2512,7 @@ bool SelectionDAG::isSplatValue(SDValue V, const APInt &DemandedElts, // Deal with some common cases here that work for both fixed and scalable // vector types. - switch (V.getOpcode()) { + switch (Opcode) { case ISD::SPLAT_VECTOR: UndefElts = V.getOperand(0).isUndef() ? APInt::getAllOnes(DemandedElts.getBitWidth()) @@ -2537,7 +2538,12 @@ bool SelectionDAG::isSplatValue(SDValue V, const APInt &DemandedElts, case ISD::SIGN_EXTEND: case ISD::ZERO_EXTEND: return isSplatValue(V.getOperand(0), DemandedElts, UndefElts, Depth + 1); - } + default: + if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN || + Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) + return TLI->isSplatValueForTargetNode(V, DemandedElts, UndefElts, Depth); + break; +} // We don't support other cases than those above for scalable vectors at // the moment. @@ -2548,7 +2554,7 @@ bool SelectionDAG::isSplatValue(SDValue V, const APInt &DemandedElts, assert(NumElts == DemandedElts.getBitWidth() && "Vector size mismatch"); UndefElts = APInt::getZero(NumElts); - switch (V.getOpcode()) { + switch (Opcode) { case ISD::BUILD_VECTOR: { SDValue Scl; for (unsigned i = 0; i != NumElts; ++i) { @@ -2600,13 +2606,30 @@ bool SelectionDAG::isSplatValue(SDValue V, const APInt &DemandedElts, } break; } + case ISD::ANY_EXTEND_VECTOR_INREG: + case ISD::SIGN_EXTEND_VECTOR_INREG: + case ISD::ZERO_EXTEND_VECTOR_INREG: { + // Widen the demanded elts by the src element count. + SDValue Src = V.getOperand(0); + // We don't support scalable vectors at the moment. + if (Src.getValueType().isScalableVector()) + return false; + unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); + APInt UndefSrcElts; + APInt DemandedSrcElts = DemandedElts.zextOrSelf(NumSrcElts); + if (isSplatValue(Src, DemandedSrcElts, UndefSrcElts, Depth + 1)) { + UndefElts = UndefSrcElts.truncOrSelf(NumElts); + return true; + } + break; + } } return false; } /// Helper wrapper to main isSplatValue function. -bool SelectionDAG::isSplatValue(SDValue V, bool AllowUndefs) { +bool SelectionDAG::isSplatValue(SDValue V, bool AllowUndefs) const { EVT VT = V.getValueType(); assert(VT.isVector() && "Vector type expected"); @@ -5291,9 +5314,10 @@ SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL, if (isUndef(Opcode, Ops)) return getUNDEF(VT); - // Handle the case of two scalars. + // Handle binops special cases. if (NumOps == 2) { - // TODO: Move foldConstantFPMath here? + if (SDValue CFP = foldConstantFPMath(Opcode, DL, VT, Ops[0], Ops[1])) + return CFP; if (auto *C1 = dyn_cast(Ops[0])) { if (auto *C2 = dyn_cast(Ops[1])) { @@ -5463,10 +5487,11 @@ SDValue SelectionDAG::foldConstantFPMath(unsigned Opcode, const SDLoc &DL, // should. That will require dealing with a potentially non-default // rounding mode, checking the "opStatus" return value from the APFloat // math calculations, and possibly other variations. - auto *N1CFP = dyn_cast(N1.getNode()); - auto *N2CFP = dyn_cast(N2.getNode()); + ConstantFPSDNode *N1CFP = isConstOrConstSplatFP(N1, /*AllowUndefs*/ false); + ConstantFPSDNode *N2CFP = isConstOrConstSplatFP(N2, /*AllowUndefs*/ false); if (N1CFP && N2CFP) { - APFloat C1 = N1CFP->getValueAPF(), C2 = N2CFP->getValueAPF(); + APFloat C1 = N1CFP->getValueAPF(); // make copy + const APFloat &C2 = N2CFP->getValueAPF(); switch (Opcode) { case ISD::FADD: C1.add(C2, APFloat::rmNearestTiesToEven); @@ -5486,6 +5511,14 @@ SDValue SelectionDAG::foldConstantFPMath(unsigned Opcode, const SDLoc &DL, case ISD::FCOPYSIGN: C1.copySign(C2); return getConstantFP(C1, DL, VT); + case ISD::FMINNUM: + return getConstantFP(minnum(C1, C2), DL, VT); + case ISD::FMAXNUM: + return getConstantFP(maxnum(C1, C2), DL, VT); + case ISD::FMINIMUM: + return getConstantFP(minimum(C1, C2), DL, VT); + case ISD::FMAXIMUM: + return getConstantFP(maximum(C1, C2), DL, VT); default: break; } } @@ -5502,8 +5535,9 @@ SDValue SelectionDAG::foldConstantFPMath(unsigned Opcode, const SDLoc &DL, switch (Opcode) { case ISD::FSUB: // -0.0 - undef --> undef (consistent with "fneg undef") - if (N1CFP && N1CFP->getValueAPF().isNegZero() && N2.isUndef()) - return getUNDEF(VT); + if (ConstantFPSDNode *N1C = isConstOrConstSplatFP(N1, /*AllowUndefs*/ true)) + if (N1C && N1C->getValueAPF().isNegZero() && N2.isUndef()) + return getUNDEF(VT); LLVM_FALLTHROUGH; case ISD::FADD: @@ -5962,9 +5996,6 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, if (SDValue SV = FoldConstantArithmetic(Opcode, DL, VT, {N1, N2})) return SV; - if (SDValue V = foldConstantFPMath(Opcode, DL, VT, N1, N2)) - return V; - // Canonicalize an UNDEF to the RHS, even over a constant. if (N1.isUndef()) { if (TLI->isCommutativeBinOp(Opcode)) { diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 7726a0007e44..63cd723cf6da 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1036,7 +1036,6 @@ void SelectionDAGBuilder::init(GCFunctionInfo *gfi, AliasAnalysis *aa, AA = aa; GFI = gfi; LibInfo = li; - DL = &DAG.getDataLayout(); Context = DAG.getContext(); LPadToCallSiteMap.clear(); SL->init(DAG.getTargetLoweringInfo(), TM, DAG.getDataLayout()); @@ -1626,6 +1625,9 @@ SDValue SelectionDAGBuilder::getValueImpl(const Value *V) { if (const auto *Equiv = dyn_cast(C)) return getValue(Equiv->getGlobalValue()); + if (const auto *NC = dyn_cast(C)) + return getValue(NC->getGlobalValue()); + VectorType *VecTy = cast(V->getType()); // Now that we know the number and type of the elements, get that number of @@ -1921,8 +1923,8 @@ void SelectionDAGBuilder::visitRet(const ReturnInst &I) { DAG.getDataLayout().getAllocaAddrSpace()), PtrValueVTs); - SDValue RetPtr = DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(), - DemoteReg, PtrValueVTs[0]); + SDValue RetPtr = + DAG.getCopyFromReg(Chain, getCurSDLoc(), DemoteReg, PtrValueVTs[0]); SDValue RetOp = getValue(I.getOperand(0)); SmallVector ValueVTs, MemVTs; @@ -2657,7 +2659,8 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD, SDLoc dl = getCurSDLoc(); SDValue StackSlotPtr = DAG.getFrameIndex(FI, PtrTy); const Module &M = *ParentBB->getParent()->getFunction().getParent(); - Align Align = DL->getPrefTypeAlign(Type::getInt8PtrTy(M.getContext())); + Align Align = + DAG.getDataLayout().getPrefTypeAlign(Type::getInt8PtrTy(M.getContext())); // Generate code to load the content of the guard slot. SDValue GuardVal = DAG.getLoad( @@ -3058,14 +3061,14 @@ void SelectionDAGBuilder::visitLandingPad(const LandingPadInst &LP) { void SelectionDAGBuilder::UpdateSplitBlock(MachineBasicBlock *First, MachineBasicBlock *Last) { // Update JTCases. - for (unsigned i = 0, e = SL->JTCases.size(); i != e; ++i) - if (SL->JTCases[i].first.HeaderBB == First) - SL->JTCases[i].first.HeaderBB = Last; + for (JumpTableBlock &JTB : SL->JTCases) + if (JTB.first.HeaderBB == First) + JTB.first.HeaderBB = Last; // Update BitTestCases. - for (unsigned i = 0, e = SL->BitTestCases.size(); i != e; ++i) - if (SL->BitTestCases[i].Parent == First) - SL->BitTestCases[i].Parent = Last; + for (BitTestBlock &BTB : SL->BitTestCases) + if (BTB.Parent == First) + BTB.Parent = Last; } void SelectionDAGBuilder::visitIndirectBr(const IndirectBrInst &I) { @@ -3111,6 +3114,8 @@ void SelectionDAGBuilder::visitUnreachable(const UnreachableInst &I) { void SelectionDAGBuilder::visitUnary(const User &I, unsigned Opcode) { SDNodeFlags Flags; + if (auto *FPOp = dyn_cast(&I)) + Flags.copyFMF(*FPOp); SDValue Op = getValue(I.getOperand(0)); SDValue UnNodeValue = DAG.getNode(Opcode, getCurSDLoc(), Op.getValueType(), @@ -3881,7 +3886,8 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) { unsigned Field = cast(Idx)->getUniqueInteger().getZExtValue(); if (Field) { // N = N + Offset - uint64_t Offset = DL->getStructLayout(StTy)->getElementOffset(Field); + uint64_t Offset = + DAG.getDataLayout().getStructLayout(StTy)->getElementOffset(Field); // In an inbounds GEP with an offset that is nonnegative even when // interpreted as signed, assume there is no unsigned overflow. @@ -3898,7 +3904,8 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) { // (and fix up the result later). unsigned IdxSize = DAG.getDataLayout().getIndexSizeInBits(AS); MVT IdxTy = MVT::getIntegerVT(IdxSize); - TypeSize ElementSize = DL->getTypeAllocSize(GTI.getIndexedType()); + TypeSize ElementSize = + DAG.getDataLayout().getTypeAllocSize(GTI.getIndexedType()); // We intentionally mask away the high bits here; ElementSize may not // fit in IdxTy. APInt ElementMul(IdxSize, ElementSize.getKnownMinSize()); @@ -4788,7 +4795,7 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I, } // Use TargetConstant instead of a regular constant for immarg. - EVT VT = TLI.getValueType(*DL, Arg->getType(), true); + EVT VT = TLI.getValueType(DAG.getDataLayout(), Arg->getType(), true); if (const ConstantInt *CI = dyn_cast(Arg)) { assert(CI->getBitWidth() <= 64 && "large intrinsic immediates not handled"); @@ -6571,7 +6578,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, } else { EVT PtrTy = TLI.getValueType(DAG.getDataLayout(), I.getType()); const Value *Global = TLI.getSDagStackGuard(M); - Align Align = DL->getPrefTypeAlign(Global->getType()); + Align Align = DAG.getDataLayout().getPrefTypeAlign(Global->getType()); Res = DAG.getLoad(PtrTy, sdl, Chain, getValue(Global), MachinePointerInfo(Global, 0), Align, MachineMemOperand::MOVolatile); @@ -7127,12 +7134,10 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, } SDValue VectorStep = DAG.getStepVector(sdl, VecTy); SDValue VectorInduction = DAG.getNode( - ISD::UADDO, sdl, DAG.getVTList(VecTy, CCVT), VectorIndex, VectorStep); - SDValue SetCC = DAG.getSetCC(sdl, CCVT, VectorInduction.getValue(0), + ISD::UADDSAT, sdl, VecTy, VectorIndex, VectorStep); + SDValue SetCC = DAG.getSetCC(sdl, CCVT, VectorInduction, VectorTripCount, ISD::CondCode::SETULT); - setValue(&I, DAG.getNode(ISD::AND, sdl, CCVT, - DAG.getNOT(sdl, VectorInduction.getValue(1), CCVT), - SetCC)); + setValue(&I, SetCC); return; } case Intrinsic::experimental_vector_insert: { @@ -7317,32 +7322,26 @@ static unsigned getISDForVPIntrinsic(const VPIntrinsic &VPIntrin) { void SelectionDAGBuilder::visitVPLoadGather(const VPIntrinsic &VPIntrin, EVT VT, SmallVector &OpValues, - bool isGather) { + bool IsGather) { SDLoc DL = getCurSDLoc(); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); Value *PtrOperand = VPIntrin.getArgOperand(0); - MaybeAlign Alignment = DAG.getEVTAlign(VT); + MaybeAlign Alignment = VPIntrin.getPointerAlignment(); + if (!Alignment) + Alignment = DAG.getEVTAlign(VT); AAMDNodes AAInfo = VPIntrin.getAAMetadata(); const MDNode *Ranges = VPIntrin.getMetadata(LLVMContext::MD_range); SDValue LD; bool AddToChain = true; - if (!isGather) { + if (!IsGather) { // Do not serialize variable-length loads of constant memory with // anything. - MemoryLocation ML; - if (VT.isScalableVector()) - ML = MemoryLocation::getAfter(PtrOperand); - else - ML = MemoryLocation( - PtrOperand, - LocationSize::precise( - DAG.getDataLayout().getTypeStoreSize(VPIntrin.getType())), - AAInfo); + MemoryLocation ML = MemoryLocation::getAfter(PtrOperand, AAInfo); AddToChain = !AA || !AA->pointsToConstantMemory(ML); SDValue InChain = AddToChain ? DAG.getRoot() : DAG.getEntryNode(); MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(PtrOperand), MachineMemOperand::MOLoad, - VT.getStoreSize().getKnownMinSize(), *Alignment, AAInfo, Ranges); + MemoryLocation::UnknownSize, *Alignment, AAInfo, Ranges); LD = DAG.getLoadVP(VT, DL, InChain, OpValues[0], OpValues[1], OpValues[2], MMO, false /*IsExpanding */); } else { @@ -7380,18 +7379,20 @@ void SelectionDAGBuilder::visitVPLoadGather(const VPIntrinsic &VPIntrin, EVT VT, void SelectionDAGBuilder::visitVPStoreScatter(const VPIntrinsic &VPIntrin, SmallVector &OpValues, - bool isScatter) { + bool IsScatter) { SDLoc DL = getCurSDLoc(); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); Value *PtrOperand = VPIntrin.getArgOperand(1); EVT VT = OpValues[0].getValueType(); - MaybeAlign Alignment = DAG.getEVTAlign(VT); + MaybeAlign Alignment = VPIntrin.getPointerAlignment(); + if (!Alignment) + Alignment = DAG.getEVTAlign(VT); AAMDNodes AAInfo = VPIntrin.getAAMetadata(); SDValue ST; - if (!isScatter) { + if (!IsScatter) { MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(PtrOperand), MachineMemOperand::MOStore, - VT.getStoreSize().getKnownMinSize(), *Alignment, AAInfo); + MemoryLocation::UnknownSize, *Alignment, AAInfo); ST = DAG.getStoreVP(getMemoryRoot(), DL, OpValues[0], OpValues[1], OpValues[2], OpValues[3], MMO, false /* IsTruncating */); @@ -7690,8 +7691,9 @@ static SDValue getMemCmpLoad(const Value *PtrVal, MVT LoadVT, LoadInput = ConstantExpr::getBitCast(const_cast(LoadInput), PointerType::getUnqual(LoadTy)); - if (const Constant *LoadCst = ConstantFoldLoadFromConstPtr( - const_cast(LoadInput), LoadTy, *Builder.DL)) + if (const Constant *LoadCst = + ConstantFoldLoadFromConstPtr(const_cast(LoadInput), + LoadTy, Builder.DAG.getDataLayout())) return Builder.getValue(LoadCst); } @@ -9646,8 +9648,8 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const { // We push in swifterror return as the last element of CLI.Ins. ArgListTy &Args = CLI.getArgs(); if (supportSwiftError()) { - for (unsigned i = 0, e = Args.size(); i != e; ++i) { - if (Args[i].IsSwiftError) { + for (const ArgListEntry &Arg : Args) { + if (Arg.IsSwiftError) { ISD::InputArg MyFlags; MyFlags.VT = getPointerTy(DL); MyFlags.ArgVT = EVT(getPointerTy(DL)); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index d6122aa0a739..ea48042a5dcf 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -190,7 +190,6 @@ public: static const unsigned LowestSDNodeOrder = 1; SelectionDAG &DAG; - const DataLayout *DL = nullptr; AAResults *AA = nullptr; const TargetLibraryInfo *LibInfo; @@ -568,9 +567,9 @@ private: void visitTargetIntrinsic(const CallInst &I, unsigned Intrinsic); void visitConstrainedFPIntrinsic(const ConstrainedFPIntrinsic &FPI); void visitVPLoadGather(const VPIntrinsic &VPIntrin, EVT VT, - SmallVector &OpValues, bool isGather); + SmallVector &OpValues, bool IsGather); void visitVPStoreScatter(const VPIntrinsic &VPIntrin, - SmallVector &OpValues, bool isScatter); + SmallVector &OpValues, bool IsScatter); void visitVectorPredicationIntrinsic(const VPIntrinsic &VPIntrin); void visitVAStart(const CallInst &I); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index c7e37cf8ca14..77e11b364588 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -297,7 +297,7 @@ TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, #ifndef NDEBUG dbgs() << "If a target marks an instruction with " "'usesCustomInserter', it must implement " - "TargetLowering::EmitInstrWithCustomInserter!"; + "TargetLowering::EmitInstrWithCustomInserter!\n"; #endif llvm_unreachable(nullptr); } @@ -1784,27 +1784,25 @@ SelectionDAGISel::FinishBasicBlock() { } // Update PHI Nodes - for (unsigned pi = 0, pe = FuncInfo->PHINodesToUpdate.size(); - pi != pe; ++pi) { - MachineInstrBuilder PHI(*MF, FuncInfo->PHINodesToUpdate[pi].first); + for (const std::pair &P : + FuncInfo->PHINodesToUpdate) { + MachineInstrBuilder PHI(*MF, P.first); MachineBasicBlock *PHIBB = PHI->getParent(); assert(PHI->isPHI() && "This is not a machine PHI node that we are updating!"); // This is "default" BB. We have two jumps to it. From "header" BB and // from last "case" BB, unless the latter was skipped. if (PHIBB == BTB.Default) { - PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second).addMBB(BTB.Parent); + PHI.addReg(P.second).addMBB(BTB.Parent); if (!BTB.ContiguousRange) { - PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second) - .addMBB(BTB.Cases.back().ThisBB); + PHI.addReg(P.second).addMBB(BTB.Cases.back().ThisBB); } } // One of "cases" BB. - for (unsigned j = 0, ej = BTB.Cases.size(); - j != ej; ++j) { - MachineBasicBlock* cBB = BTB.Cases[j].ThisBB; + for (const SwitchCG::BitTestCase &BT : BTB.Cases) { + MachineBasicBlock* cBB = BT.ThisBB; if (cBB->isSuccessor(PHIBB)) - PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second).addMBB(cBB); + PHI.addReg(P.second).addMBB(cBB); } } } diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 737695b5eabe..e6b06ab93d6b 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -3136,6 +3136,19 @@ bool TargetLowering::isKnownNeverNaNForTargetNode(SDValue Op, return false; } +bool TargetLowering::isSplatValueForTargetNode(SDValue Op, + const APInt &DemandedElts, + APInt &UndefElts, + unsigned Depth) const { + assert((Op.getOpcode() >= ISD::BUILTIN_OP_END || + Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || + Op.getOpcode() == ISD::INTRINSIC_W_CHAIN || + Op.getOpcode() == ISD::INTRINSIC_VOID) && + "Should use isSplatValue if you don't know whether Op" + " is a target node!"); + return false; +} + // FIXME: Ideally, this would use ISD::isConstantSplatVector(), but that must // work with truncating build vectors and vectors with elements of less than // 8 bits. @@ -4853,13 +4866,9 @@ TargetLowering::ParseConstraints(const DataLayout &DL, } // Now select chosen alternative in each constraint. - for (unsigned cIndex = 0, eIndex = ConstraintOperands.size(); - cIndex != eIndex; ++cIndex) { - AsmOperandInfo &cInfo = ConstraintOperands[cIndex]; - if (cInfo.Type == InlineAsm::isClobber) - continue; - cInfo.selectAlternative(bestMAIndex); - } + for (AsmOperandInfo &cInfo : ConstraintOperands) + if (cInfo.Type != InlineAsm::isClobber) + cInfo.selectAlternative(bestMAIndex); } } @@ -4927,9 +4936,9 @@ TargetLowering::ConstraintWeight ConstraintWeight BestWeight = CW_Invalid; // Loop over the options, keeping track of the most general one. - for (unsigned i = 0, e = rCodes->size(); i != e; ++i) { + for (const std::string &rCode : *rCodes) { ConstraintWeight weight = - getSingleConstraintMatchWeight(info, (*rCodes)[i].c_str()); + getSingleConstraintMatchWeight(info, rCode.c_str()); if (weight > BestWeight) BestWeight = weight; } @@ -6550,15 +6559,15 @@ static bool isNonZeroModBitWidthOrUndef(SDValue Z, unsigned BW) { true); } -bool TargetLowering::expandFunnelShift(SDNode *Node, SDValue &Result, - SelectionDAG &DAG) const { +SDValue TargetLowering::expandFunnelShift(SDNode *Node, + SelectionDAG &DAG) const { EVT VT = Node->getValueType(0); if (VT.isVector() && (!isOperationLegalOrCustom(ISD::SHL, VT) || !isOperationLegalOrCustom(ISD::SRL, VT) || !isOperationLegalOrCustom(ISD::SUB, VT) || !isOperationLegalOrCustomOrPromote(ISD::OR, VT))) - return false; + return SDValue(); SDValue X = Node->getOperand(0); SDValue Y = Node->getOperand(1); @@ -6592,8 +6601,7 @@ bool TargetLowering::expandFunnelShift(SDNode *Node, SDValue &Result, } Z = DAG.getNOT(DL, Z, ShVT); } - Result = DAG.getNode(RevOpcode, DL, VT, X, Y, Z); - return true; + return DAG.getNode(RevOpcode, DL, VT, X, Y, Z); } SDValue ShX, ShY; @@ -6633,13 +6641,12 @@ bool TargetLowering::expandFunnelShift(SDNode *Node, SDValue &Result, ShY = DAG.getNode(ISD::SRL, DL, VT, Y, ShAmt); } } - Result = DAG.getNode(ISD::OR, DL, VT, ShX, ShY); - return true; + return DAG.getNode(ISD::OR, DL, VT, ShX, ShY); } // TODO: Merge with expandFunnelShift. -bool TargetLowering::expandROT(SDNode *Node, bool AllowVectorOps, - SDValue &Result, SelectionDAG &DAG) const { +SDValue TargetLowering::expandROT(SDNode *Node, bool AllowVectorOps, + SelectionDAG &DAG) const { EVT VT = Node->getValueType(0); unsigned EltSizeInBits = VT.getScalarSizeInBits(); bool IsLeft = Node->getOpcode() == ISD::ROTL; @@ -6650,12 +6657,12 @@ bool TargetLowering::expandROT(SDNode *Node, bool AllowVectorOps, EVT ShVT = Op1.getValueType(); SDValue Zero = DAG.getConstant(0, DL, ShVT); - // If a rotate in the other direction is supported, use it. + // If a rotate in the other direction is more supported, use it. unsigned RevRot = IsLeft ? ISD::ROTR : ISD::ROTL; - if (isOperationLegalOrCustom(RevRot, VT) && isPowerOf2_32(EltSizeInBits)) { + if (!isOperationLegalOrCustom(Node->getOpcode(), VT) && + isOperationLegalOrCustom(RevRot, VT) && isPowerOf2_32(EltSizeInBits)) { SDValue Sub = DAG.getNode(ISD::SUB, DL, ShVT, Zero, Op1); - Result = DAG.getNode(RevRot, DL, VT, Op0, Sub); - return true; + return DAG.getNode(RevRot, DL, VT, Op0, Sub); } if (!AllowVectorOps && VT.isVector() && @@ -6664,7 +6671,7 @@ bool TargetLowering::expandROT(SDNode *Node, bool AllowVectorOps, !isOperationLegalOrCustom(ISD::SUB, VT) || !isOperationLegalOrCustomOrPromote(ISD::OR, VT) || !isOperationLegalOrCustomOrPromote(ISD::AND, VT))) - return false; + return SDValue(); unsigned ShOpc = IsLeft ? ISD::SHL : ISD::SRL; unsigned HsOpc = IsLeft ? ISD::SRL : ISD::SHL; @@ -6690,8 +6697,7 @@ bool TargetLowering::expandROT(SDNode *Node, bool AllowVectorOps, HsVal = DAG.getNode(HsOpc, DL, VT, DAG.getNode(HsOpc, DL, VT, Op0, One), HsAmt); } - Result = DAG.getNode(ISD::OR, DL, VT, ShVal, HsVal); - return true; + return DAG.getNode(ISD::OR, DL, VT, ShVal, HsVal); } void TargetLowering::expandShiftParts(SDNode *Node, SDValue &Lo, SDValue &Hi, @@ -8048,7 +8054,8 @@ SDValue TargetLowering::expandIntMINMAX(SDNode *Node, SelectionDAG &DAG) const { if (VT.isVector() && !isOperationLegalOrCustom(ISD::VSELECT, VT)) return DAG.UnrollVectorOp(Node); - SDValue Cond = DAG.getSetCC(DL, VT, Op0, Op1, CC); + EVT BoolVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); + SDValue Cond = DAG.getSetCC(DL, BoolVT, Op0, Op1, CC); return DAG.getSelect(DL, VT, Cond, Op0, Op1); } diff --git a/llvm/lib/CodeGen/ShadowStackGCLowering.cpp b/llvm/lib/CodeGen/ShadowStackGCLowering.cpp index 86b559fd6413..43a54ce33bf0 100644 --- a/llvm/lib/CodeGen/ShadowStackGCLowering.cpp +++ b/llvm/lib/CodeGen/ShadowStackGCLowering.cpp @@ -162,8 +162,8 @@ Type *ShadowStackGCLowering::GetConcreteStackEntryType(Function &F) { // doInitialization creates the generic version of this type. std::vector EltTys; EltTys.push_back(StackEntryTy); - for (size_t I = 0; I != Roots.size(); I++) - EltTys.push_back(Roots[I].second->getAllocatedType()); + for (const std::pair &Root : Roots) + EltTys.push_back(Root.second->getAllocatedType()); return StructType::create(EltTys, ("gc_stackentry." + F.getName()).str()); } @@ -240,8 +240,8 @@ void ShadowStackGCLowering::CollectRoots(Function &F) { SmallVector, 16> MetaRoots; for (BasicBlock &BB : F) - for (BasicBlock::iterator II = BB.begin(), E = BB.end(); II != E;) - if (IntrinsicInst *CI = dyn_cast(II++)) + for (Instruction &I : BB) + if (IntrinsicInst *CI = dyn_cast(&I)) if (Function *F = CI->getCalledFunction()) if (F->getIntrinsicID() == Intrinsic::gcroot) { std::pair Pair = std::make_pair( @@ -377,9 +377,9 @@ bool ShadowStackGCLowering::runOnFunction(Function &F) { // Delete the original allocas (which are no longer used) and the intrinsic // calls (which are no longer valid). Doing this last avoids invalidating // iterators. - for (unsigned I = 0, E = Roots.size(); I != E; ++I) { - Roots[I].first->eraseFromParent(); - Roots[I].second->eraseFromParent(); + for (std::pair &Root : Roots) { + Root.first->eraseFromParent(); + Root.second->eraseFromParent(); } Roots.clear(); diff --git a/llvm/lib/CodeGen/StackMapLivenessAnalysis.cpp b/llvm/lib/CodeGen/StackMapLivenessAnalysis.cpp index 5ccfacfc26dc..3640296adbca 100644 --- a/llvm/lib/CodeGen/StackMapLivenessAnalysis.cpp +++ b/llvm/lib/CodeGen/StackMapLivenessAnalysis.cpp @@ -131,15 +131,15 @@ bool StackMapLiveness::calculateLiveness(MachineFunction &MF) { bool HasStackMap = false; // Reverse iterate over all instructions and add the current live register // set to an instruction if we encounter a patchpoint instruction. - for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) { - if (I->getOpcode() == TargetOpcode::PATCHPOINT) { - addLiveOutSetToMI(MF, *I); + for (MachineInstr &MI : llvm::reverse(MBB)) { + if (MI.getOpcode() == TargetOpcode::PATCHPOINT) { + addLiveOutSetToMI(MF, MI); HasChanged = true; HasStackMap = true; ++NumStackMaps; } - LLVM_DEBUG(dbgs() << " " << LiveRegs << " " << *I); - LiveRegs.stepBackward(*I); + LLVM_DEBUG(dbgs() << " " << LiveRegs << " " << MI); + LiveRegs.stepBackward(MI); } ++NumBBsVisited; if (!HasStackMap) diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp index 7445f77c955d..6765fd274686 100644 --- a/llvm/lib/CodeGen/StackProtector.cpp +++ b/llvm/lib/CodeGen/StackProtector.cpp @@ -162,7 +162,7 @@ bool StackProtector::ContainsProtectableArray(Type *Ty, bool &IsLarge, } bool StackProtector::HasAddressTaken(const Instruction *AI, - uint64_t AllocSize) { + TypeSize AllocSize) { const DataLayout &DL = M->getDataLayout(); for (const User *U : AI->users()) { const auto *I = cast(U); @@ -170,7 +170,8 @@ bool StackProtector::HasAddressTaken(const Instruction *AI, // the bounds of the allocated object. Optional MemLoc = MemoryLocation::getOrNone(I); if (MemLoc.hasValue() && MemLoc->Size.hasValue() && - MemLoc->Size.getValue() > AllocSize) + !TypeSize::isKnownGE(AllocSize, + TypeSize::getFixed(MemLoc->Size.getValue()))) return true; switch (I->getOpcode()) { case Instruction::Store: @@ -203,13 +204,19 @@ bool StackProtector::HasAddressTaken(const Instruction *AI, // would use it could also be out-of-bounds meaning stack protection is // required. const GetElementPtrInst *GEP = cast(I); - unsigned TypeSize = DL.getIndexTypeSizeInBits(I->getType()); - APInt Offset(TypeSize, 0); - APInt MaxOffset(TypeSize, AllocSize); - if (!GEP->accumulateConstantOffset(DL, Offset) || Offset.ugt(MaxOffset)) + unsigned IndexSize = DL.getIndexTypeSizeInBits(I->getType()); + APInt Offset(IndexSize, 0); + if (!GEP->accumulateConstantOffset(DL, Offset)) + return true; + TypeSize OffsetSize = TypeSize::Fixed(Offset.getLimitedValue()); + if (!TypeSize::isKnownGT(AllocSize, OffsetSize)) return true; // Adjust AllocSize to be the space remaining after this offset. - if (HasAddressTaken(I, AllocSize - Offset.getLimitedValue())) + // We can't subtract a fixed size from a scalable one, so in that case + // assume the scalable value is of minimum size. + TypeSize NewAllocSize = + TypeSize::Fixed(AllocSize.getKnownMinValue()) - OffsetSize; + if (HasAddressTaken(I, NewAllocSize)) return true; break; } diff --git a/llvm/lib/CodeGen/StackSlotColoring.cpp b/llvm/lib/CodeGen/StackSlotColoring.cpp index f49ba5ccd447..17e6f51d0899 100644 --- a/llvm/lib/CodeGen/StackSlotColoring.cpp +++ b/llvm/lib/CodeGen/StackSlotColoring.cpp @@ -325,8 +325,7 @@ bool StackSlotColoring::ColorSlots(MachineFunction &MF) { LLVM_DEBUG(dbgs() << "Color spill slot intervals:\n"); bool Changed = false; - for (unsigned i = 0, e = SSIntervals.size(); i != e; ++i) { - LiveInterval *li = SSIntervals[i]; + for (LiveInterval *li : SSIntervals) { int SS = Register::stackSlot2Index(li->reg()); int NewSS = ColorSlot(li); assert(NewSS >= 0 && "Stack coloring failed?"); @@ -338,8 +337,7 @@ bool StackSlotColoring::ColorSlots(MachineFunction &MF) { } LLVM_DEBUG(dbgs() << "\nSpill slots after coloring:\n"); - for (unsigned i = 0, e = SSIntervals.size(); i != e; ++i) { - LiveInterval *li = SSIntervals[i]; + for (LiveInterval *li : SSIntervals) { int SS = Register::stackSlot2Index(li->reg()); li->setWeight(SlotWeights[SS]); } @@ -347,8 +345,8 @@ bool StackSlotColoring::ColorSlots(MachineFunction &MF) { llvm::stable_sort(SSIntervals, IntervalSorter()); #ifndef NDEBUG - for (unsigned i = 0, e = SSIntervals.size(); i != e; ++i) - LLVM_DEBUG(SSIntervals[i]->dump()); + for (LiveInterval *li : SSIntervals) + LLVM_DEBUG(li->dump()); LLVM_DEBUG(dbgs() << '\n'); #endif diff --git a/llvm/lib/CodeGen/TailDuplicator.cpp b/llvm/lib/CodeGen/TailDuplicator.cpp index 54fc6ee45d00..68a7b80d6146 100644 --- a/llvm/lib/CodeGen/TailDuplicator.cpp +++ b/llvm/lib/CodeGen/TailDuplicator.cpp @@ -207,35 +207,34 @@ bool TailDuplicator::tailDuplicateAndUpdate( // Add the new vregs as available values. DenseMap::iterator LI = SSAUpdateVals.find(VReg); - for (unsigned j = 0, ee = LI->second.size(); j != ee; ++j) { - MachineBasicBlock *SrcBB = LI->second[j].first; - Register SrcReg = LI->second[j].second; + for (std::pair &J : LI->second) { + MachineBasicBlock *SrcBB = J.first; + Register SrcReg = J.second; SSAUpdate.AddAvailableValue(SrcBB, SrcReg); } + SmallVector DebugUses; // Rewrite uses that are outside of the original def's block. - MachineRegisterInfo::use_iterator UI = MRI->use_begin(VReg); - // Only remove instructions after loop, as DBG_VALUE_LISTs with multiple - // uses of VReg may invalidate the use iterator when erased. - SmallPtrSet InstrsToRemove; - while (UI != MRI->use_end()) { - MachineOperand &UseMO = *UI; + for (MachineOperand &UseMO : + llvm::make_early_inc_range(MRI->use_operands(VReg))) { MachineInstr *UseMI = UseMO.getParent(); - ++UI; + // Rewrite debug uses last so that they can take advantage of any + // register mappings introduced by other users in its BB, since we + // cannot create new register definitions specifically for the debug + // instruction (as debug instructions should not affect CodeGen). if (UseMI->isDebugValue()) { - // SSAUpdate can replace the use with an undef. That creates - // a debug instruction that is a kill. - // FIXME: Should it SSAUpdate job to delete debug instructions - // instead of replacing the use with undef? - InstrsToRemove.insert(UseMI); + DebugUses.push_back(&UseMO); continue; } if (UseMI->getParent() == DefBB && !UseMI->isPHI()) continue; SSAUpdate.RewriteUse(UseMO); } - for (auto *MI : InstrsToRemove) - MI->eraseFromParent(); + for (auto *UseMO : DebugUses) { + MachineInstr *UseMI = UseMO->getParent(); + UseMO->setReg( + SSAUpdate.GetValueInMiddleOfBlock(UseMI->getParent(), true)); + } } SSAUpdateVRs.clear(); @@ -511,8 +510,8 @@ void TailDuplicator::updateSuccessorsPHIs( SSAUpdateVals.find(Reg); if (LI != SSAUpdateVals.end()) { // This register is defined in the tail block. - for (unsigned j = 0, ee = LI->second.size(); j != ee; ++j) { - MachineBasicBlock *SrcBB = LI->second[j].first; + for (const std::pair &J : LI->second) { + MachineBasicBlock *SrcBB = J.first; // If we didn't duplicate a bb into a particular predecessor, we // might still have added an entry to SSAUpdateVals to correcly // recompute SSA. If that case, avoid adding a dummy extra argument @@ -520,7 +519,7 @@ void TailDuplicator::updateSuccessorsPHIs( if (!SrcBB->isSuccessor(SuccBB)) continue; - Register SrcReg = LI->second[j].second; + Register SrcReg = J.second; if (Idx != 0) { MI.getOperand(Idx).setReg(SrcReg); MI.getOperand(Idx + 1).setMBB(SrcBB); @@ -531,8 +530,7 @@ void TailDuplicator::updateSuccessorsPHIs( } } else { // Live in tail block, must also be live in predecessors. - for (unsigned j = 0, ee = TDBBs.size(); j != ee; ++j) { - MachineBasicBlock *SrcBB = TDBBs[j]; + for (MachineBasicBlock *SrcBB : TDBBs) { if (Idx != 0) { MI.getOperand(Idx).setReg(Reg); MI.getOperand(Idx + 1).setMBB(SrcBB); diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp index 5119dac36713..3f22cc4289f2 100644 --- a/llvm/lib/CodeGen/TargetInstrInfo.cpp +++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp @@ -436,7 +436,7 @@ MachineInstr &TargetInstrInfo::duplicate(MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore, const MachineInstr &Orig) const { assert(!Orig.isNotDuplicable() && "Instruction cannot be duplicated"); MachineFunction &MF = *MBB.getParent(); - return MF.CloneMachineInstrBundle(MBB, InsertBefore, Orig); + return MF.cloneMachineInstrBundle(MBB, InsertBefore, Orig); } // If the COPY instruction in MI can be folded to a stack operation, return @@ -1418,3 +1418,16 @@ void TargetInstrInfo::mergeOutliningCandidateAttributes( })) F.addFnAttr(Attribute::NoUnwind); } + +bool TargetInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB, + unsigned &Flags) const { + // Some instrumentations create special TargetOpcode at the start which + // expands to special code sequences which must be present. + auto First = MBB.getFirstNonDebugInstr(); + if (First != MBB.end() && + (First->getOpcode() == TargetOpcode::FENTRY_CALL || + First->getOpcode() == TargetOpcode::PATCHABLE_FUNCTION_ENTER)) + return false; + + return true; +} diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp index c0a7efff9e98..6fc6881f8736 100644 --- a/llvm/lib/CodeGen/TargetLoweringBase.cpp +++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp @@ -1187,7 +1187,7 @@ TargetLoweringBase::emitPatchPoint(MachineInstr &InitialMI, // all stack slots), but we need to handle the different type of stackmap // operands and memory effects here. - if (!llvm::any_of(MI->operands(), + if (llvm::none_of(MI->operands(), [](MachineOperand &Operand) { return Operand.isFI(); })) return MBB; diff --git a/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/llvm/lib/CodeGen/TargetRegisterInfo.cpp index f4bb71535f7f..f5cb518fce3e 100644 --- a/llvm/lib/CodeGen/TargetRegisterInfo.cpp +++ b/llvm/lib/CodeGen/TargetRegisterInfo.cpp @@ -248,8 +248,8 @@ static void getAllocatableSetForRC(const MachineFunction &MF, const TargetRegisterClass *RC, BitVector &R){ assert(RC->isAllocatable() && "invalid for nonallocatable sets"); ArrayRef Order = RC->getRawAllocationOrder(MF); - for (unsigned i = 0; i != Order.size(); ++i) - R.set(Order[i]); + for (MCPhysReg PR : Order) + R.set(PR); } BitVector TargetRegisterInfo::getAllocatableSet(const MachineFunction &MF, diff --git a/llvm/lib/CodeGen/UnreachableBlockElim.cpp b/llvm/lib/CodeGen/UnreachableBlockElim.cpp index c9a19948ff2f..3426a03b6083 100644 --- a/llvm/lib/CodeGen/UnreachableBlockElim.cpp +++ b/llvm/lib/CodeGen/UnreachableBlockElim.cpp @@ -144,23 +144,22 @@ bool UnreachableMachineBlockElim::runOnMachineFunction(MachineFunction &F) { } // Actually remove the blocks now. - for (unsigned i = 0, e = DeadBlocks.size(); i != e; ++i) { + for (MachineBasicBlock *BB : DeadBlocks) { // Remove any call site information for calls in the block. - for (auto &I : DeadBlocks[i]->instrs()) + for (auto &I : BB->instrs()) if (I.shouldUpdateCallSiteInfo()) - DeadBlocks[i]->getParent()->eraseCallSiteInfo(&I); + BB->getParent()->eraseCallSiteInfo(&I); - DeadBlocks[i]->eraseFromParent(); + BB->eraseFromParent(); } // Cleanup PHI nodes. - for (MachineFunction::iterator I = F.begin(), E = F.end(); I != E; ++I) { - MachineBasicBlock *BB = &*I; + for (MachineBasicBlock &BB : F) { // Prune unneeded PHI entries. - SmallPtrSet preds(BB->pred_begin(), - BB->pred_end()); - MachineBasicBlock::iterator phi = BB->begin(); - while (phi != BB->end() && phi->isPHI()) { + SmallPtrSet preds(BB.pred_begin(), + BB.pred_end()); + MachineBasicBlock::iterator phi = BB.begin(); + while (phi != BB.end() && phi->isPHI()) { for (unsigned i = phi->getNumOperands() - 1; i >= 2; i-=2) if (!preds.count(phi->getOperand(i).getMBB())) { phi->RemoveOperand(i); @@ -189,7 +188,7 @@ bool UnreachableMachineBlockElim::runOnMachineFunction(MachineFunction &F) { // insert a COPY instead of simply replacing the output // with the input. const TargetInstrInfo *TII = F.getSubtarget().getInstrInfo(); - BuildMI(*BB, BB->getFirstNonPHI(), phi->getDebugLoc(), + BuildMI(BB, BB.getFirstNonPHI(), phi->getDebugLoc(), TII->get(TargetOpcode::COPY), OutputReg) .addReg(InputReg, getRegState(Input), InputSub); } diff --git a/llvm/lib/CodeGen/VLIWMachineScheduler.cpp b/llvm/lib/CodeGen/VLIWMachineScheduler.cpp new file mode 100644 index 000000000000..cbc5d9ec169b --- /dev/null +++ b/llvm/lib/CodeGen/VLIWMachineScheduler.cpp @@ -0,0 +1,1009 @@ +//===- VLIWMachineScheduler.cpp - VLIW-Focused Scheduling Pass ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// MachineScheduler schedules machine instructions after phi elimination. It +// preserves LiveIntervals so it can be invoked before register allocation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/VLIWMachineScheduler.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/DFAPacketizer.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/RegisterClassInfo.h" +#include "llvm/CodeGen/RegisterPressure.h" +#include "llvm/CodeGen/ScheduleDAG.h" +#include "llvm/CodeGen/ScheduleHazardRecognizer.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetOpcodes.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetSchedule.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "machine-scheduler" + +static cl::opt IgnoreBBRegPressure("ignore-bb-reg-pressure", cl::Hidden, + cl::ZeroOrMore, cl::init(false)); + +static cl::opt UseNewerCandidate("use-newer-candidate", cl::Hidden, + cl::ZeroOrMore, cl::init(true)); + +static cl::opt SchedDebugVerboseLevel("misched-verbose-level", + cl::Hidden, cl::ZeroOrMore, + cl::init(1)); + +// Check if the scheduler should penalize instructions that are available to +// early due to a zero-latency dependence. +static cl::opt CheckEarlyAvail("check-early-avail", cl::Hidden, + cl::ZeroOrMore, cl::init(true)); + +// This value is used to determine if a register class is a high pressure set. +// We compute the maximum number of registers needed and divided by the total +// available. Then, we compare the result to this value. +static cl::opt RPThreshold("vliw-misched-reg-pressure", cl::Hidden, + cl::init(0.75f), + cl::desc("High register pressure threhold.")); + +VLIWResourceModel::VLIWResourceModel(const TargetSubtargetInfo &STI, + const TargetSchedModel *SM) + : TII(STI.getInstrInfo()), SchedModel(SM) { + ResourcesModel = createPacketizer(STI); + + // This hard requirement could be relaxed, + // but for now do not let it proceed. + assert(ResourcesModel && "Unimplemented CreateTargetScheduleState."); + + Packet.reserve(SchedModel->getIssueWidth()); + Packet.clear(); + ResourcesModel->clearResources(); +} + +void VLIWResourceModel::reset() { + Packet.clear(); + ResourcesModel->clearResources(); +} + +VLIWResourceModel::~VLIWResourceModel() { delete ResourcesModel; } + +/// Return true if there is a dependence between SUd and SUu. +bool VLIWResourceModel::hasDependence(const SUnit *SUd, const SUnit *SUu) { + if (SUd->Succs.size() == 0) + return false; + + for (const auto &S : SUd->Succs) { + // Since we do not add pseudos to packets, might as well + // ignore order dependencies. + if (S.isCtrl()) + continue; + + if (S.getSUnit() == SUu && S.getLatency() > 0) + return true; + } + return false; +} + +/// Check if scheduling of this SU is possible +/// in the current packet. +/// It is _not_ precise (statefull), it is more like +/// another heuristic. Many corner cases are figured +/// empirically. +bool VLIWResourceModel::isResourceAvailable(SUnit *SU, bool IsTop) { + if (!SU || !SU->getInstr()) + return false; + + // First see if the pipeline could receive this instruction + // in the current cycle. + switch (SU->getInstr()->getOpcode()) { + default: + if (!ResourcesModel->canReserveResources(*SU->getInstr())) + return false; + break; + case TargetOpcode::EXTRACT_SUBREG: + case TargetOpcode::INSERT_SUBREG: + case TargetOpcode::SUBREG_TO_REG: + case TargetOpcode::REG_SEQUENCE: + case TargetOpcode::IMPLICIT_DEF: + case TargetOpcode::COPY: + case TargetOpcode::INLINEASM: + case TargetOpcode::INLINEASM_BR: + break; + } + + // Now see if there are no other dependencies to instructions already + // in the packet. + if (IsTop) { + for (unsigned i = 0, e = Packet.size(); i != e; ++i) + if (hasDependence(Packet[i], SU)) + return false; + } else { + for (unsigned i = 0, e = Packet.size(); i != e; ++i) + if (hasDependence(SU, Packet[i])) + return false; + } + return true; +} + +/// Keep track of available resources. +bool VLIWResourceModel::reserveResources(SUnit *SU, bool IsTop) { + bool startNewCycle = false; + // Artificially reset state. + if (!SU) { + reset(); + TotalPackets++; + return false; + } + // If this SU does not fit in the packet or the packet is now full + // start a new one. + if (!isResourceAvailable(SU, IsTop) || + Packet.size() >= SchedModel->getIssueWidth()) { + reset(); + TotalPackets++; + startNewCycle = true; + } + + switch (SU->getInstr()->getOpcode()) { + default: + ResourcesModel->reserveResources(*SU->getInstr()); + break; + case TargetOpcode::EXTRACT_SUBREG: + case TargetOpcode::INSERT_SUBREG: + case TargetOpcode::SUBREG_TO_REG: + case TargetOpcode::REG_SEQUENCE: + case TargetOpcode::IMPLICIT_DEF: + case TargetOpcode::KILL: + case TargetOpcode::CFI_INSTRUCTION: + case TargetOpcode::EH_LABEL: + case TargetOpcode::COPY: + case TargetOpcode::INLINEASM: + case TargetOpcode::INLINEASM_BR: + break; + } + Packet.push_back(SU); + +#ifndef NDEBUG + LLVM_DEBUG(dbgs() << "Packet[" << TotalPackets << "]:\n"); + for (unsigned i = 0, e = Packet.size(); i != e; ++i) { + LLVM_DEBUG(dbgs() << "\t[" << i << "] SU("); + LLVM_DEBUG(dbgs() << Packet[i]->NodeNum << ")\t"); + LLVM_DEBUG(Packet[i]->getInstr()->dump()); + } +#endif + + return startNewCycle; +} + +DFAPacketizer * +VLIWResourceModel::createPacketizer(const TargetSubtargetInfo &STI) const { + return STI.getInstrInfo()->CreateTargetScheduleState(STI); +} + +/// schedule - Called back from MachineScheduler::runOnMachineFunction +/// after setting up the current scheduling region. [RegionBegin, RegionEnd) +/// only includes instructions that have DAG nodes, not scheduling boundaries. +void VLIWMachineScheduler::schedule() { + LLVM_DEBUG(dbgs() << "********** MI Converging Scheduling VLIW " + << printMBBReference(*BB) << " " << BB->getName() + << " in_func " << BB->getParent()->getName() + << " at loop depth " << MLI->getLoopDepth(BB) << " \n"); + + buildDAGWithRegPressure(); + + Topo.InitDAGTopologicalSorting(); + + // Postprocess the DAG to add platform-specific artificial dependencies. + postprocessDAG(); + + SmallVector TopRoots, BotRoots; + findRootsAndBiasEdges(TopRoots, BotRoots); + + // Initialize the strategy before modifying the DAG. + SchedImpl->initialize(this); + + LLVM_DEBUG({ + unsigned maxH = 0; + for (const SUnit &SU : SUnits) + if (SU.getHeight() > maxH) + maxH = SU.getHeight(); + dbgs() << "Max Height " << maxH << "\n"; + }); + LLVM_DEBUG({ + unsigned maxD = 0; + for (const SUnit &SU : SUnits) + if (SU.getDepth() > maxD) + maxD = SU.getDepth(); + dbgs() << "Max Depth " << maxD << "\n"; + }); + LLVM_DEBUG(dump()); + if (ViewMISchedDAGs) + viewGraph(); + + initQueues(TopRoots, BotRoots); + + bool IsTopNode = false; + while (true) { + LLVM_DEBUG( + dbgs() << "** VLIWMachineScheduler::schedule picking next node\n"); + SUnit *SU = SchedImpl->pickNode(IsTopNode); + if (!SU) + break; + + if (!checkSchedLimit()) + break; + + scheduleMI(SU, IsTopNode); + + // Notify the scheduling strategy after updating the DAG. + SchedImpl->schedNode(SU, IsTopNode); + + updateQueues(SU, IsTopNode); + } + assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone."); + + placeDebugValues(); + + LLVM_DEBUG({ + dbgs() << "*** Final schedule for " + << printMBBReference(*begin()->getParent()) << " ***\n"; + dumpSchedule(); + dbgs() << '\n'; + }); +} + +void ConvergingVLIWScheduler::initialize(ScheduleDAGMI *dag) { + DAG = static_cast(dag); + SchedModel = DAG->getSchedModel(); + + Top.init(DAG, SchedModel); + Bot.init(DAG, SchedModel); + + // Initialize the HazardRecognizers. If itineraries don't exist, are empty, or + // are disabled, then these HazardRecs will be disabled. + const InstrItineraryData *Itin = DAG->getSchedModel()->getInstrItineraries(); + const TargetSubtargetInfo &STI = DAG->MF.getSubtarget(); + const TargetInstrInfo *TII = STI.getInstrInfo(); + delete Top.HazardRec; + delete Bot.HazardRec; + Top.HazardRec = TII->CreateTargetMIHazardRecognizer(Itin, DAG); + Bot.HazardRec = TII->CreateTargetMIHazardRecognizer(Itin, DAG); + + delete Top.ResourceModel; + delete Bot.ResourceModel; + Top.ResourceModel = createVLIWResourceModel(STI, DAG->getSchedModel()); + Bot.ResourceModel = createVLIWResourceModel(STI, DAG->getSchedModel()); + + const std::vector &MaxPressure = + DAG->getRegPressure().MaxSetPressure; + HighPressureSets.assign(MaxPressure.size(), 0); + for (unsigned i = 0, e = MaxPressure.size(); i < e; ++i) { + unsigned Limit = DAG->getRegClassInfo()->getRegPressureSetLimit(i); + HighPressureSets[i] = + ((float)MaxPressure[i] > ((float)Limit * RPThreshold)); + } + + assert((!ForceTopDown || !ForceBottomUp) && + "-misched-topdown incompatible with -misched-bottomup"); +} + +VLIWResourceModel *ConvergingVLIWScheduler::createVLIWResourceModel( + const TargetSubtargetInfo &STI, const TargetSchedModel *SchedModel) const { + return new VLIWResourceModel(STI, SchedModel); +} + +void ConvergingVLIWScheduler::releaseTopNode(SUnit *SU) { + for (const SDep &PI : SU->Preds) { + unsigned PredReadyCycle = PI.getSUnit()->TopReadyCycle; + unsigned MinLatency = PI.getLatency(); +#ifndef NDEBUG + Top.MaxMinLatency = std::max(MinLatency, Top.MaxMinLatency); +#endif + if (SU->TopReadyCycle < PredReadyCycle + MinLatency) + SU->TopReadyCycle = PredReadyCycle + MinLatency; + } + + if (!SU->isScheduled) + Top.releaseNode(SU, SU->TopReadyCycle); +} + +void ConvergingVLIWScheduler::releaseBottomNode(SUnit *SU) { + assert(SU->getInstr() && "Scheduled SUnit must have instr"); + + for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); I != E; + ++I) { + unsigned SuccReadyCycle = I->getSUnit()->BotReadyCycle; + unsigned MinLatency = I->getLatency(); +#ifndef NDEBUG + Bot.MaxMinLatency = std::max(MinLatency, Bot.MaxMinLatency); +#endif + if (SU->BotReadyCycle < SuccReadyCycle + MinLatency) + SU->BotReadyCycle = SuccReadyCycle + MinLatency; + } + + if (!SU->isScheduled) + Bot.releaseNode(SU, SU->BotReadyCycle); +} + +ConvergingVLIWScheduler::VLIWSchedBoundary::~VLIWSchedBoundary() { + delete ResourceModel; + delete HazardRec; +} + +/// Does this SU have a hazard within the current instruction group. +/// +/// The scheduler supports two modes of hazard recognition. The first is the +/// ScheduleHazardRecognizer API. It is a fully general hazard recognizer that +/// supports highly complicated in-order reservation tables +/// (ScoreboardHazardRecognizer) and arbitrary target-specific logic. +/// +/// The second is a streamlined mechanism that checks for hazards based on +/// simple counters that the scheduler itself maintains. It explicitly checks +/// for instruction dispatch limitations, including the number of micro-ops that +/// can dispatch per cycle. +/// +/// TODO: Also check whether the SU must start a new group. +bool ConvergingVLIWScheduler::VLIWSchedBoundary::checkHazard(SUnit *SU) { + if (HazardRec->isEnabled()) + return HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard; + + unsigned uops = SchedModel->getNumMicroOps(SU->getInstr()); + if (IssueCount + uops > SchedModel->getIssueWidth()) + return true; + + return false; +} + +void ConvergingVLIWScheduler::VLIWSchedBoundary::releaseNode( + SUnit *SU, unsigned ReadyCycle) { + if (ReadyCycle < MinReadyCycle) + MinReadyCycle = ReadyCycle; + + // Check for interlocks first. For the purpose of other heuristics, an + // instruction that cannot issue appears as if it's not in the ReadyQueue. + if (ReadyCycle > CurrCycle || checkHazard(SU)) + + Pending.push(SU); + else + Available.push(SU); +} + +/// Move the boundary of scheduled code by one cycle. +void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpCycle() { + unsigned Width = SchedModel->getIssueWidth(); + IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width; + + assert(MinReadyCycle < std::numeric_limits::max() && + "MinReadyCycle uninitialized"); + unsigned NextCycle = std::max(CurrCycle + 1, MinReadyCycle); + + if (!HazardRec->isEnabled()) { + // Bypass HazardRec virtual calls. + CurrCycle = NextCycle; + } else { + // Bypass getHazardType calls in case of long latency. + for (; CurrCycle != NextCycle; ++CurrCycle) { + if (isTop()) + HazardRec->AdvanceCycle(); + else + HazardRec->RecedeCycle(); + } + } + CheckPending = true; + + LLVM_DEBUG(dbgs() << "*** Next cycle " << Available.getName() << " cycle " + << CurrCycle << '\n'); +} + +/// Move the boundary of scheduled code by one SUnit. +void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpNode(SUnit *SU) { + bool startNewCycle = false; + + // Update the reservation table. + if (HazardRec->isEnabled()) { + if (!isTop() && SU->isCall) { + // Calls are scheduled with their preceding instructions. For bottom-up + // scheduling, clear the pipeline state before emitting. + HazardRec->Reset(); + } + HazardRec->EmitInstruction(SU); + } + + // Update DFA model. + startNewCycle = ResourceModel->reserveResources(SU, isTop()); + + // Check the instruction group dispatch limit. + // TODO: Check if this SU must end a dispatch group. + IssueCount += SchedModel->getNumMicroOps(SU->getInstr()); + if (startNewCycle) { + LLVM_DEBUG(dbgs() << "*** Max instrs at cycle " << CurrCycle << '\n'); + bumpCycle(); + } else + LLVM_DEBUG(dbgs() << "*** IssueCount " << IssueCount << " at cycle " + << CurrCycle << '\n'); +} + +/// Release pending ready nodes in to the available queue. This makes them +/// visible to heuristics. +void ConvergingVLIWScheduler::VLIWSchedBoundary::releasePending() { + // If the available queue is empty, it is safe to reset MinReadyCycle. + if (Available.empty()) + MinReadyCycle = std::numeric_limits::max(); + + // Check to see if any of the pending instructions are ready to issue. If + // so, add them to the available queue. + for (unsigned i = 0, e = Pending.size(); i != e; ++i) { + SUnit *SU = *(Pending.begin() + i); + unsigned ReadyCycle = isTop() ? SU->TopReadyCycle : SU->BotReadyCycle; + + if (ReadyCycle < MinReadyCycle) + MinReadyCycle = ReadyCycle; + + if (ReadyCycle > CurrCycle) + continue; + + if (checkHazard(SU)) + continue; + + Available.push(SU); + Pending.remove(Pending.begin() + i); + --i; + --e; + } + CheckPending = false; +} + +/// Remove SU from the ready set for this boundary. +void ConvergingVLIWScheduler::VLIWSchedBoundary::removeReady(SUnit *SU) { + if (Available.isInQueue(SU)) + Available.remove(Available.find(SU)); + else { + assert(Pending.isInQueue(SU) && "bad ready count"); + Pending.remove(Pending.find(SU)); + } +} + +/// If this queue only has one ready candidate, return it. As a side effect, +/// advance the cycle until at least one node is ready. If multiple instructions +/// are ready, return NULL. +SUnit *ConvergingVLIWScheduler::VLIWSchedBoundary::pickOnlyChoice() { + if (CheckPending) + releasePending(); + + auto AdvanceCycle = [this]() { + if (Available.empty()) + return true; + if (Available.size() == 1 && Pending.size() > 0) + return !ResourceModel->isResourceAvailable(*Available.begin(), isTop()) || + getWeakLeft(*Available.begin(), isTop()) != 0; + return false; + }; + for (unsigned i = 0; AdvanceCycle(); ++i) { + assert(i <= (HazardRec->getMaxLookAhead() + MaxMinLatency) && + "permanent hazard"); + (void)i; + ResourceModel->reserveResources(nullptr, isTop()); + bumpCycle(); + releasePending(); + } + if (Available.size() == 1) + return *Available.begin(); + return nullptr; +} + +#ifndef NDEBUG +void ConvergingVLIWScheduler::traceCandidate(const char *Label, + const ReadyQueue &Q, SUnit *SU, + int Cost, PressureChange P) { + dbgs() << Label << " " << Q.getName() << " "; + if (P.isValid()) + dbgs() << DAG->TRI->getRegPressureSetName(P.getPSet()) << ":" + << P.getUnitInc() << " "; + else + dbgs() << " "; + dbgs() << "cost(" << Cost << ")\t"; + DAG->dumpNode(*SU); +} + +// Very detailed queue dump, to be used with higher verbosity levels. +void ConvergingVLIWScheduler::readyQueueVerboseDump( + const RegPressureTracker &RPTracker, SchedCandidate &Candidate, + ReadyQueue &Q) { + RegPressureTracker &TempTracker = const_cast(RPTracker); + + dbgs() << ">>> " << Q.getName() << "\n"; + for (ReadyQueue::iterator I = Q.begin(), E = Q.end(); I != E; ++I) { + RegPressureDelta RPDelta; + TempTracker.getMaxPressureDelta((*I)->getInstr(), RPDelta, + DAG->getRegionCriticalPSets(), + DAG->getRegPressure().MaxSetPressure); + std::stringstream dbgstr; + dbgstr << "SU(" << std::setw(3) << (*I)->NodeNum << ")"; + dbgs() << dbgstr.str(); + SchedulingCost(Q, *I, Candidate, RPDelta, true); + dbgs() << "\t"; + (*I)->getInstr()->dump(); + } + dbgs() << "\n"; +} +#endif + +/// isSingleUnscheduledPred - If SU2 is the only unscheduled predecessor +/// of SU, return true (we may have duplicates) +static inline bool isSingleUnscheduledPred(SUnit *SU, SUnit *SU2) { + if (SU->NumPredsLeft == 0) + return false; + + for (auto &Pred : SU->Preds) { + // We found an available, but not scheduled, predecessor. + if (!Pred.getSUnit()->isScheduled && (Pred.getSUnit() != SU2)) + return false; + } + + return true; +} + +/// isSingleUnscheduledSucc - If SU2 is the only unscheduled successor +/// of SU, return true (we may have duplicates) +static inline bool isSingleUnscheduledSucc(SUnit *SU, SUnit *SU2) { + if (SU->NumSuccsLeft == 0) + return false; + + for (auto &Succ : SU->Succs) { + // We found an available, but not scheduled, successor. + if (!Succ.getSUnit()->isScheduled && (Succ.getSUnit() != SU2)) + return false; + } + return true; +} + +/// Check if the instruction changes the register pressure of a register in the +/// high pressure set. The function returns a negative value if the pressure +/// decreases and a positive value is the pressure increases. If the instruction +/// doesn't use a high pressure register or doesn't change the register +/// pressure, then return 0. +int ConvergingVLIWScheduler::pressureChange(const SUnit *SU, bool isBotUp) { + PressureDiff &PD = DAG->getPressureDiff(SU); + for (auto &P : PD) { + if (!P.isValid()) + continue; + // The pressure differences are computed bottom-up, so the comparision for + // an increase is positive in the bottom direction, but negative in the + // top-down direction. + if (HighPressureSets[P.getPSet()]) + return (isBotUp ? P.getUnitInc() : -P.getUnitInc()); + } + return 0; +} + +/// Single point to compute overall scheduling cost. +/// TODO: More heuristics will be used soon. +int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU, + SchedCandidate &Candidate, + RegPressureDelta &Delta, + bool verbose) { + // Initial trivial priority. + int ResCount = 1; + + // Do not waste time on a node that is already scheduled. + if (!SU || SU->isScheduled) + return ResCount; + + LLVM_DEBUG(if (verbose) dbgs() + << ((Q.getID() == TopQID) ? "(top|" : "(bot|")); + // Forced priority is high. + if (SU->isScheduleHigh) { + ResCount += PriorityOne; + LLVM_DEBUG(dbgs() << "H|"); + } + + unsigned IsAvailableAmt = 0; + // Critical path first. + if (Q.getID() == TopQID) { + if (Top.isLatencyBound(SU)) { + LLVM_DEBUG(if (verbose) dbgs() << "LB|"); + ResCount += (SU->getHeight() * ScaleTwo); + } + + LLVM_DEBUG(if (verbose) { + std::stringstream dbgstr; + dbgstr << "h" << std::setw(3) << SU->getHeight() << "|"; + dbgs() << dbgstr.str(); + }); + + // If resources are available for it, multiply the + // chance of scheduling. + if (Top.ResourceModel->isResourceAvailable(SU, true)) { + IsAvailableAmt = (PriorityTwo + PriorityThree); + ResCount += IsAvailableAmt; + LLVM_DEBUG(if (verbose) dbgs() << "A|"); + } else + LLVM_DEBUG(if (verbose) dbgs() << " |"); + } else { + if (Bot.isLatencyBound(SU)) { + LLVM_DEBUG(if (verbose) dbgs() << "LB|"); + ResCount += (SU->getDepth() * ScaleTwo); + } + + LLVM_DEBUG(if (verbose) { + std::stringstream dbgstr; + dbgstr << "d" << std::setw(3) << SU->getDepth() << "|"; + dbgs() << dbgstr.str(); + }); + + // If resources are available for it, multiply the + // chance of scheduling. + if (Bot.ResourceModel->isResourceAvailable(SU, false)) { + IsAvailableAmt = (PriorityTwo + PriorityThree); + ResCount += IsAvailableAmt; + LLVM_DEBUG(if (verbose) dbgs() << "A|"); + } else + LLVM_DEBUG(if (verbose) dbgs() << " |"); + } + + unsigned NumNodesBlocking = 0; + if (Q.getID() == TopQID) { + // How many SUs does it block from scheduling? + // Look at all of the successors of this node. + // Count the number of nodes that + // this node is the sole unscheduled node for. + if (Top.isLatencyBound(SU)) + for (const SDep &SI : SU->Succs) + if (isSingleUnscheduledPred(SI.getSUnit(), SU)) + ++NumNodesBlocking; + } else { + // How many unscheduled predecessors block this node? + if (Bot.isLatencyBound(SU)) + for (const SDep &PI : SU->Preds) + if (isSingleUnscheduledSucc(PI.getSUnit(), SU)) + ++NumNodesBlocking; + } + ResCount += (NumNodesBlocking * ScaleTwo); + + LLVM_DEBUG(if (verbose) { + std::stringstream dbgstr; + dbgstr << "blk " << std::setw(2) << NumNodesBlocking << ")|"; + dbgs() << dbgstr.str(); + }); + + // Factor in reg pressure as a heuristic. + if (!IgnoreBBRegPressure) { + // Decrease priority by the amount that register pressure exceeds the limit. + ResCount -= (Delta.Excess.getUnitInc() * PriorityOne); + // Decrease priority if register pressure exceeds the limit. + ResCount -= (Delta.CriticalMax.getUnitInc() * PriorityOne); + // Decrease priority slightly if register pressure would increase over the + // current maximum. + ResCount -= (Delta.CurrentMax.getUnitInc() * PriorityTwo); + // If there are register pressure issues, then we remove the value added for + // the instruction being available. The rationale is that we really don't + // want to schedule an instruction that causes a spill. + if (IsAvailableAmt && pressureChange(SU, Q.getID() != TopQID) > 0 && + (Delta.Excess.getUnitInc() || Delta.CriticalMax.getUnitInc() || + Delta.CurrentMax.getUnitInc())) + ResCount -= IsAvailableAmt; + LLVM_DEBUG(if (verbose) { + dbgs() << "RP " << Delta.Excess.getUnitInc() << "/" + << Delta.CriticalMax.getUnitInc() << "/" + << Delta.CurrentMax.getUnitInc() << ")|"; + }); + } + + // Give preference to a zero latency instruction if the dependent + // instruction is in the current packet. + if (Q.getID() == TopQID && getWeakLeft(SU, true) == 0) { + for (const SDep &PI : SU->Preds) { + if (!PI.getSUnit()->getInstr()->isPseudo() && PI.isAssignedRegDep() && + PI.getLatency() == 0 && + Top.ResourceModel->isInPacket(PI.getSUnit())) { + ResCount += PriorityThree; + LLVM_DEBUG(if (verbose) dbgs() << "Z|"); + } + } + } else if (Q.getID() == BotQID && getWeakLeft(SU, false) == 0) { + for (const SDep &SI : SU->Succs) { + if (!SI.getSUnit()->getInstr()->isPseudo() && SI.isAssignedRegDep() && + SI.getLatency() == 0 && + Bot.ResourceModel->isInPacket(SI.getSUnit())) { + ResCount += PriorityThree; + LLVM_DEBUG(if (verbose) dbgs() << "Z|"); + } + } + } + + // If the instruction has a non-zero latency dependence with an instruction in + // the current packet, then it should not be scheduled yet. The case occurs + // when the dependent instruction is scheduled in a new packet, so the + // scheduler updates the current cycle and pending instructions become + // available. + if (CheckEarlyAvail) { + if (Q.getID() == TopQID) { + for (const auto &PI : SU->Preds) { + if (PI.getLatency() > 0 && + Top.ResourceModel->isInPacket(PI.getSUnit())) { + ResCount -= PriorityOne; + LLVM_DEBUG(if (verbose) dbgs() << "D|"); + } + } + } else { + for (const auto &SI : SU->Succs) { + if (SI.getLatency() > 0 && + Bot.ResourceModel->isInPacket(SI.getSUnit())) { + ResCount -= PriorityOne; + LLVM_DEBUG(if (verbose) dbgs() << "D|"); + } + } + } + } + + LLVM_DEBUG(if (verbose) { + std::stringstream dbgstr; + dbgstr << "Total " << std::setw(4) << ResCount << ")"; + dbgs() << dbgstr.str(); + }); + + return ResCount; +} + +/// Pick the best candidate from the top queue. +/// +/// TODO: getMaxPressureDelta results can be mostly cached for each SUnit during +/// DAG building. To adjust for the current scheduling location we need to +/// maintain the number of vreg uses remaining to be top-scheduled. +ConvergingVLIWScheduler::CandResult +ConvergingVLIWScheduler::pickNodeFromQueue(VLIWSchedBoundary &Zone, + const RegPressureTracker &RPTracker, + SchedCandidate &Candidate) { + ReadyQueue &Q = Zone.Available; + LLVM_DEBUG(if (SchedDebugVerboseLevel > 1) + readyQueueVerboseDump(RPTracker, Candidate, Q); + else Q.dump();); + + // getMaxPressureDelta temporarily modifies the tracker. + RegPressureTracker &TempTracker = const_cast(RPTracker); + + // BestSU remains NULL if no top candidates beat the best existing candidate. + CandResult FoundCandidate = NoCand; + for (ReadyQueue::iterator I = Q.begin(), E = Q.end(); I != E; ++I) { + RegPressureDelta RPDelta; + TempTracker.getMaxPressureDelta((*I)->getInstr(), RPDelta, + DAG->getRegionCriticalPSets(), + DAG->getRegPressure().MaxSetPressure); + + int CurrentCost = SchedulingCost(Q, *I, Candidate, RPDelta, false); + + // Initialize the candidate if needed. + if (!Candidate.SU) { + LLVM_DEBUG(traceCandidate("DCAND", Q, *I, CurrentCost)); + Candidate.SU = *I; + Candidate.RPDelta = RPDelta; + Candidate.SCost = CurrentCost; + FoundCandidate = NodeOrder; + continue; + } + + // Choose node order for negative cost candidates. There is no good + // candidate in this case. + if (CurrentCost < 0 && Candidate.SCost < 0) { + if ((Q.getID() == TopQID && (*I)->NodeNum < Candidate.SU->NodeNum) || + (Q.getID() == BotQID && (*I)->NodeNum > Candidate.SU->NodeNum)) { + LLVM_DEBUG(traceCandidate("NCAND", Q, *I, CurrentCost)); + Candidate.SU = *I; + Candidate.RPDelta = RPDelta; + Candidate.SCost = CurrentCost; + FoundCandidate = NodeOrder; + } + continue; + } + + // Best cost. + if (CurrentCost > Candidate.SCost) { + LLVM_DEBUG(traceCandidate("CCAND", Q, *I, CurrentCost)); + Candidate.SU = *I; + Candidate.RPDelta = RPDelta; + Candidate.SCost = CurrentCost; + FoundCandidate = BestCost; + continue; + } + + // Choose an instruction that does not depend on an artificial edge. + unsigned CurrWeak = getWeakLeft(*I, (Q.getID() == TopQID)); + unsigned CandWeak = getWeakLeft(Candidate.SU, (Q.getID() == TopQID)); + if (CurrWeak != CandWeak) { + if (CurrWeak < CandWeak) { + LLVM_DEBUG(traceCandidate("WCAND", Q, *I, CurrentCost)); + Candidate.SU = *I; + Candidate.RPDelta = RPDelta; + Candidate.SCost = CurrentCost; + FoundCandidate = Weak; + } + continue; + } + + if (CurrentCost == Candidate.SCost && Zone.isLatencyBound(*I)) { + unsigned CurrSize, CandSize; + if (Q.getID() == TopQID) { + CurrSize = (*I)->Succs.size(); + CandSize = Candidate.SU->Succs.size(); + } else { + CurrSize = (*I)->Preds.size(); + CandSize = Candidate.SU->Preds.size(); + } + if (CurrSize > CandSize) { + LLVM_DEBUG(traceCandidate("SPCAND", Q, *I, CurrentCost)); + Candidate.SU = *I; + Candidate.RPDelta = RPDelta; + Candidate.SCost = CurrentCost; + FoundCandidate = BestCost; + } + // Keep the old candidate if it's a better candidate. That is, don't use + // the subsequent tie breaker. + if (CurrSize != CandSize) + continue; + } + + // Tie breaker. + // To avoid scheduling indeterminism, we need a tie breaker + // for the case when cost is identical for two nodes. + if (UseNewerCandidate && CurrentCost == Candidate.SCost) { + if ((Q.getID() == TopQID && (*I)->NodeNum < Candidate.SU->NodeNum) || + (Q.getID() == BotQID && (*I)->NodeNum > Candidate.SU->NodeNum)) { + LLVM_DEBUG(traceCandidate("TCAND", Q, *I, CurrentCost)); + Candidate.SU = *I; + Candidate.RPDelta = RPDelta; + Candidate.SCost = CurrentCost; + FoundCandidate = NodeOrder; + continue; + } + } + + // Fall through to original instruction order. + // Only consider node order if Candidate was chosen from this Q. + if (FoundCandidate == NoCand) + continue; + } + return FoundCandidate; +} + +/// Pick the best candidate node from either the top or bottom queue. +SUnit *ConvergingVLIWScheduler::pickNodeBidrectional(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()) { + LLVM_DEBUG(dbgs() << "Picked only Bottom\n"); + IsTopNode = false; + return SU; + } + if (SUnit *SU = Top.pickOnlyChoice()) { + LLVM_DEBUG(dbgs() << "Picked only Top\n"); + IsTopNode = true; + return SU; + } + SchedCandidate BotCand; + // Prefer bottom scheduling when heuristics are silent. + CandResult BotResult = + pickNodeFromQueue(Bot, DAG->getBotRPTracker(), BotCand); + assert(BotResult != NoCand && "failed to find the first candidate"); + + // If either Q has a single candidate that provides the least increase in + // Excess pressure, we can immediately schedule from that Q. + // + // RegionCriticalPSets summarizes the pressure within the scheduled region and + // affects picking from either Q. If scheduling in one direction must + // increase pressure for one of the excess PSets, then schedule in that + // direction first to provide more freedom in the other direction. + if (BotResult == SingleExcess || BotResult == SingleCritical) { + LLVM_DEBUG(dbgs() << "Prefered Bottom Node\n"); + IsTopNode = false; + return BotCand.SU; + } + // Check if the top Q has a better candidate. + SchedCandidate TopCand; + CandResult TopResult = + pickNodeFromQueue(Top, DAG->getTopRPTracker(), TopCand); + assert(TopResult != NoCand && "failed to find the first candidate"); + + if (TopResult == SingleExcess || TopResult == SingleCritical) { + LLVM_DEBUG(dbgs() << "Prefered Top Node\n"); + IsTopNode = true; + return TopCand.SU; + } + // If either Q has a single candidate that minimizes pressure above the + // original region's pressure pick it. + if (BotResult == SingleMax) { + LLVM_DEBUG(dbgs() << "Prefered Bottom Node SingleMax\n"); + IsTopNode = false; + return BotCand.SU; + } + if (TopResult == SingleMax) { + LLVM_DEBUG(dbgs() << "Prefered Top Node SingleMax\n"); + IsTopNode = true; + return TopCand.SU; + } + if (TopCand.SCost > BotCand.SCost) { + LLVM_DEBUG(dbgs() << "Prefered Top Node Cost\n"); + IsTopNode = true; + return TopCand.SU; + } + // Otherwise prefer the bottom candidate in node order. + LLVM_DEBUG(dbgs() << "Prefered Bottom in Node order\n"); + IsTopNode = false; + return BotCand.SU; +} + +/// Pick the best node to balance the schedule. Implements MachineSchedStrategy. +SUnit *ConvergingVLIWScheduler::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; + if (ForceTopDown) { + SU = Top.pickOnlyChoice(); + if (!SU) { + SchedCandidate TopCand; + CandResult TopResult = + pickNodeFromQueue(Top, DAG->getTopRPTracker(), TopCand); + assert(TopResult != NoCand && "failed to find the first candidate"); + (void)TopResult; + SU = TopCand.SU; + } + IsTopNode = true; + } else if (ForceBottomUp) { + SU = Bot.pickOnlyChoice(); + if (!SU) { + SchedCandidate BotCand; + CandResult BotResult = + pickNodeFromQueue(Bot, DAG->getBotRPTracker(), BotCand); + assert(BotResult != NoCand && "failed to find the first candidate"); + (void)BotResult; + SU = BotCand.SU; + } + IsTopNode = false; + } else { + SU = pickNodeBidrectional(IsTopNode); + } + if (SU->isTopReady()) + Top.removeReady(SU); + if (SU->isBottomReady()) + Bot.removeReady(SU); + + LLVM_DEBUG(dbgs() << "*** " << (IsTopNode ? "Top" : "Bottom") + << " Scheduling instruction in cycle " + << (IsTopNode ? Top.CurrCycle : Bot.CurrCycle) << " (" + << reportPackets() << ")\n"; + DAG->dumpNode(*SU)); + return SU; +} + +/// Update the scheduler's state after scheduling a node. This is the same node +/// that was just returned by pickNode(). However, VLIWMachineScheduler needs +/// to update it's state based on the current cycle before MachineSchedStrategy +/// does. +void ConvergingVLIWScheduler::schedNode(SUnit *SU, bool IsTopNode) { + if (IsTopNode) { + Top.bumpNode(SU); + SU->TopReadyCycle = Top.CurrCycle; + } else { + Bot.bumpNode(SU); + SU->BotReadyCycle = Bot.CurrCycle; + } +} diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp index 4876b9e23717..0c42bef82005 100644 --- a/llvm/lib/CodeGen/ValueTypes.cpp +++ b/llvm/lib/CodeGen/ValueTypes.cpp @@ -201,9 +201,11 @@ Type *EVT::getTypeForEVT(LLVMContext &Context) const { case MVT::x86amx: return Type::getX86_AMXTy(Context); case MVT::i64x8: return IntegerType::get(Context, 512); case MVT::externref: + // pointer to opaque struct in addrspace(10) return PointerType::get(StructType::create(Context), 10); case MVT::funcref: - return PointerType::get(StructType::create(Context), 20); + // pointer to i8 addrspace(20) + return PointerType::get(Type::getInt8Ty(Context), 20); case MVT::v1i1: return FixedVectorType::get(Type::getInt1Ty(Context), 1); case MVT::v2i1: diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp index 4564aa1c1278..d31183e46d65 100644 --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/lib/CodeGen/WinEHPrepare.cpp @@ -573,9 +573,7 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn, const auto *CatchSwitch = cast(Pad); int CatchState = -1, FollowerState = -1; SmallVector CatchBlocks(CatchSwitch->handlers()); - for (auto CBI = CatchBlocks.rbegin(), CBE = CatchBlocks.rend(); - CBI != CBE; ++CBI, FollowerState = CatchState) { - const BasicBlock *CatchBlock = *CBI; + for (const BasicBlock *CatchBlock : llvm::reverse(CatchBlocks)) { // Create the entry for this catch with the appropriate handler // properties. const auto *Catch = cast(CatchBlock->getFirstNonPHI()); @@ -591,6 +589,7 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn, Worklist.emplace_back(I, CatchState); // Remember this catch's state. FuncInfo.EHPadStateMap[Catch] = CatchState; + FollowerState = CatchState; } // Associate the catchswitch with the state of its first catch. assert(CatchSwitch->getNumHandlers()); @@ -601,11 +600,9 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn, // Step two: record the TryParentState of each state. For cleanuppads that // don't have cleanuprets, we may need to infer this from their child pads, // so visit pads in descendant-most to ancestor-most order. - for (auto Entry = FuncInfo.ClrEHUnwindMap.rbegin(), - End = FuncInfo.ClrEHUnwindMap.rend(); - Entry != End; ++Entry) { + for (ClrEHUnwindMapEntry &Entry : llvm::reverse(FuncInfo.ClrEHUnwindMap)) { const Instruction *Pad = - Entry->Handler.get()->getFirstNonPHI(); + Entry.Handler.get()->getFirstNonPHI(); // For most pads, the TryParentState is the state associated with the // unwind dest of exceptional exits from it. const BasicBlock *UnwindDest; @@ -615,7 +612,7 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn, // that's not the unwind dest of exceptions escaping the catch. Those // cases were already assigned a TryParentState in the first pass, so // skip them. - if (Entry->TryParentState != -1) + if (Entry.TryParentState != -1) continue; // Otherwise, get the unwind dest from the catchswitch. UnwindDest = Catch->getCatchSwitch()->getUnwindDest(); @@ -692,7 +689,7 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn, UnwindDestState = FuncInfo.EHPadStateMap[UnwindDest->getFirstNonPHI()]; } - Entry->TryParentState = UnwindDestState; + Entry.TryParentState = UnwindDestState; } // Step three: transfer information from pads to invokes. diff --git a/llvm/lib/CodeGen/XRayInstrumentation.cpp b/llvm/lib/CodeGen/XRayInstrumentation.cpp index 11d1b309aa64..b66429d8a5bf 100644 --- a/llvm/lib/CodeGen/XRayInstrumentation.cpp +++ b/llvm/lib/CodeGen/XRayInstrumentation.cpp @@ -226,6 +226,7 @@ bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) { case Triple::ArchType::arm: case Triple::ArchType::thumb: case Triple::ArchType::aarch64: + case Triple::ArchType::hexagon: case Triple::ArchType::mips: case Triple::ArchType::mipsel: case Triple::ArchType::mips64: diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp index a3dec6c25e44..ae0859e1ecfd 100644 --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -223,22 +223,21 @@ static void analyzeImportedModule( SysRoot = CU.getSysRoot(); if (!SysRoot.empty() && Path.startswith(SysRoot)) return; - if (Optional Val = DIE.find(dwarf::DW_AT_name)) - if (Optional Name = Val->getAsCString()) { - auto &Entry = (*ParseableSwiftInterfaces)[*Name]; - // The prepend path is applied later when copying. - DWARFDie CUDie = CU.getOrigUnit().getUnitDIE(); - SmallString<128> ResolvedPath; - if (sys::path::is_relative(Path)) - resolveRelativeObjectPath(ResolvedPath, CUDie); - sys::path::append(ResolvedPath, Path); - if (!Entry.empty() && Entry != ResolvedPath) - ReportWarning( - Twine("Conflicting parseable interfaces for Swift Module ") + - *Name + ": " + Entry + " and " + Path, - DIE); - Entry = std::string(ResolvedPath.str()); - } + Optional Name = dwarf::toString(DIE.find(dwarf::DW_AT_name)); + if (!Name) + return; + auto &Entry = (*ParseableSwiftInterfaces)[*Name]; + // The prepend path is applied later when copying. + DWARFDie CUDie = CU.getOrigUnit().getUnitDIE(); + SmallString<128> ResolvedPath; + if (sys::path::is_relative(Path)) + resolveRelativeObjectPath(ResolvedPath, CUDie); + sys::path::append(ResolvedPath, Path); + if (!Entry.empty() && Entry != ResolvedPath) + ReportWarning(Twine("Conflicting parseable interfaces for Swift Module ") + + *Name + ": " + Entry + " and " + Path, + DIE); + Entry = std::string(ResolvedPath.str()); } /// The distinct types of work performed by the work loop in @@ -409,10 +408,10 @@ static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) { void DWARFLinker::cleanupAuxiliarryData(LinkContext &Context) { Context.clear(); - for (auto I = DIEBlocks.begin(), E = DIEBlocks.end(); I != E; ++I) - (*I)->~DIEBlock(); - for (auto I = DIELocs.begin(), E = DIELocs.end(); I != E; ++I) - (*I)->~DIELoc(); + for (DIEBlock *I : DIEBlocks) + I->~DIEBlock(); + for (DIELoc *I : DIELocs) + I->~DIELoc(); DIEBlocks.clear(); DIELocs.clear(); @@ -846,7 +845,7 @@ void DWARFLinker::assignAbbrev(DIEAbbrev &Abbrev) { unsigned DWARFLinker::DIECloner::cloneStringAttribute( DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val, const DWARFUnit &U, OffsetsStringPool &StringPool, AttributesInfo &Info) { - Optional String = Val.getAsCString(); + Optional String = dwarf::toString(Val); if (!String) return 0; @@ -1423,6 +1422,11 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, Flags |= TF_InFunctionScope; if (!Info.InDebugMap && LLVM_LIKELY(!Update)) Flags |= TF_SkipPC; + } else if (Abbrev->getTag() == dwarf::DW_TAG_variable) { + // Function-local globals could be in the debug map even when the function + // is not, e.g., inlined functions. + if ((Flags & TF_InFunctionScope) && Info.InDebugMap) + Flags &= ~TF_SkipPC; } for (const auto &AttrSpec : Abbrev->attributes()) { diff --git a/llvm/lib/DWARFLinker/DWARFStreamer.cpp b/llvm/lib/DWARFLinker/DWARFStreamer.cpp index 46e7457f2368..1ab6ead3b5f6 100644 --- a/llvm/lib/DWARFLinker/DWARFStreamer.cpp +++ b/llvm/lib/DWARFLinker/DWARFStreamer.cpp @@ -531,9 +531,7 @@ void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params, unsigned RowsSinceLastSequence = 0; - for (unsigned Idx = 0; Idx < Rows.size(); ++Idx) { - auto &Row = Rows[Idx]; - + for (DWARFDebugLine::Row &Row : Rows) { int64_t AddressDelta; if (Address == -1ULL) { MS->emitIntValue(dwarf::DW_LNS_extended_op, 1); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index c8331487f282..95135c95e8d2 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -1195,7 +1195,7 @@ void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) Die = Origin; if (auto NameAttr = Die.find(DW_AT_name)) - if (Optional Name = NameAttr->getAsCString()) + if (Optional Name = dwarf::toString(*NameAttr)) Local.Name = *Name; if (auto Type = Die.getAttributeValueAsReferencedDie(DW_AT_type)) Local.Size = getTypeSize(Type, getCUAddrSize()); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index bda41b1f34e9..f36d3f87257a 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -1331,8 +1331,8 @@ Optional DWARFDebugLine::LineTable::getSourceByIndex(uint64_t FileInd if (Kind == FileLineInfoKind::None || !Prologue.hasFileAtIndex(FileIndex)) return None; const FileNameEntry &Entry = Prologue.getFileNameEntry(FileIndex); - if (Optional source = Entry.Source.getAsCString()) - return StringRef(*source); + if (auto E = dwarf::toString(Entry.Source)) + return StringRef(*E); return None; } @@ -1350,10 +1350,10 @@ bool DWARFDebugLine::Prologue::getFileNameByIndex( if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex)) return false; const FileNameEntry &Entry = getFileNameEntry(FileIndex); - Optional Name = Entry.Name.getAsCString(); - if (!Name) + auto E = dwarf::toString(Entry.Name); + if (!E) return false; - StringRef FileName = *Name; + StringRef FileName = *E; if (Kind == FileLineInfoKind::RawValue || isPathAbsoluteOnWindowsOrPosix(FileName)) { Result = std::string(FileName); @@ -1372,11 +1372,10 @@ bool DWARFDebugLine::Prologue::getFileNameByIndex( // relative names. if ((Entry.DirIdx != 0 || Kind != FileLineInfoKind::RelativeFilePath) && Entry.DirIdx < IncludeDirectories.size()) - IncludeDir = IncludeDirectories[Entry.DirIdx].getAsCString().getValue(); + IncludeDir = dwarf::toStringRef(IncludeDirectories[Entry.DirIdx]); } else { if (0 < Entry.DirIdx && Entry.DirIdx <= IncludeDirectories.size()) - IncludeDir = - IncludeDirectories[Entry.DirIdx - 1].getAsCString().getValue(); + IncludeDir = dwarf::toStringRef(IncludeDirectories[Entry.DirIdx - 1]); } // For absolute paths only, include the compilation directory of compile unit. diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp index cdffb36741c8..f39c7871d603 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -41,9 +41,7 @@ public: } // namespace static Error createResolverError(uint32_t Index, unsigned Kind) { - return createStringError(errc::invalid_argument, - "Unable to resolve indirect address %u for: %s", - Index, dwarf::LocListEncodingString(Kind).data()); + return make_error(Index, (dwarf::LoclistEntries)Kind); } Expected> @@ -404,3 +402,10 @@ void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size, OS << '\n'; } } + +void llvm::ResolverError::log(raw_ostream &OS) const { + OS << format("unable to resolve indirect address %u for: %s", Index, + dwarf::LocListEncodingString(Kind).data()); +} + +char llvm::ResolverError::ID; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp index 80ffd81b3403..7a81d7ff064b 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp @@ -194,13 +194,11 @@ Error DWARFDebugMacro::parseImpl( if (MacroContributionOffset == MacroToUnits.end()) return createStringError(errc::invalid_argument, "Macro contribution of the unit not found"); - Optional StrOffset = + Expected StrOffset = MacroContributionOffset->second->getStringOffsetSectionItem( Data.getULEB128(&Offset)); if (!StrOffset) - return createStringError( - errc::invalid_argument, - "String offsets contribution of the unit not found"); + return StrOffset.takeError(); E.MacroStr = MacroContributionOffset->second->getStringExtractor().getCStr( &*StrOffset); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index ed50f2635738..5421b2d59a1b 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -89,7 +89,6 @@ static void dumpLocationList(raw_ostream &OS, const DWARFFormValue &FormValue, U->getLocationTable().dumpLocationList(&Offset, OS, U->getBaseAddress(), MRI, Ctx.getDWARFObj(), U, DumpOpts, Indent); - return; } static void dumpLocationExpr(raw_ostream &OS, const DWARFFormValue &FormValue, @@ -105,7 +104,6 @@ static void dumpLocationExpr(raw_ostream &OS, const DWARFFormValue &FormValue, Ctx.isLittleEndian(), 0); DWARFExpression(Data, U->getAddressByteSize(), U->getFormParams().Format) .print(OS, DumpOpts, MRI, U); - return; } static DWARFDie resolveReferencedType(DWARFDie D, @@ -672,6 +670,8 @@ struct DWARFTypePrinter { return; if (D.getTag() == DW_TAG_subprogram) return; + if (D.getTag() == DW_TAG_lexical_block) + return; D = D.resolveTypeUnitReference(); if (DWARFDie P = D.getParent()) appendScopes(P); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp index d0fbd702e831..e19f5b8138fa 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -217,8 +217,8 @@ static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS, if (DumpOpts.Verbose) OS << format("0x%08" PRIx64 " -> ", Operands[Operand]); OS << format("0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]); - if (auto Name = Die.find(dwarf::DW_AT_name)) - OS << " \"" << Name->getAsCString() << "\""; + if (auto Name = dwarf::toString(Die.find(dwarf::DW_AT_name))) + OS << " \"" << *Name << "\""; } else { OS << format(" ", Operands[Operand]); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp index cea0f63bbf81..86991a3949dd 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -613,50 +613,53 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { } void DWARFFormValue::dumpString(raw_ostream &OS) const { - Optional DbgStr = getAsCString(); - if (DbgStr.hasValue()) { + if (auto DbgStr = dwarf::toString(*this)) { auto COS = WithColor(OS, HighlightColor::String); COS.get() << '"'; - COS.get().write_escaped(DbgStr.getValue()); + COS.get().write_escaped(*DbgStr); COS.get() << '"'; } } -Optional DWARFFormValue::getAsCString() const { +Expected DWARFFormValue::getAsCString() const { if (!isFormClass(FC_String)) - return None; + return make_error("Invalid form for string attribute", + inconvertibleErrorCode()); if (Form == DW_FORM_string) return Value.cstr; // FIXME: Add support for DW_FORM_GNU_strp_alt if (Form == DW_FORM_GNU_strp_alt || C == nullptr) - return None; + return make_error("Unsupported form for string attribute", + inconvertibleErrorCode()); uint64_t Offset = Value.uval; - if (Form == DW_FORM_line_strp) { - // .debug_line_str is tracked in the Context. - if (const char *Str = C->getLineStringExtractor().getCStr(&Offset)) - return Str; - return None; - } + Optional Index; if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx || Form == DW_FORM_strx1 || Form == DW_FORM_strx2 || Form == DW_FORM_strx3 || Form == DW_FORM_strx4) { if (!U) - return None; - Optional StrOffset = U->getStringOffsetSectionItem(Offset); + return make_error("API limitation - string extraction not " + "available without a DWARFUnit", + inconvertibleErrorCode()); + Expected StrOffset = U->getStringOffsetSectionItem(Offset); + Index = Offset; if (!StrOffset) - return None; + return StrOffset.takeError(); Offset = *StrOffset; } // Prefer the Unit's string extractor, because for .dwo it will point to // .debug_str.dwo, while the Context's extractor always uses .debug_str. - if (U) { - if (const char *Str = U->getStringExtractor().getCStr(&Offset)) - return Str; - return None; - } - if (const char *Str = C->getStringExtractor().getCStr(&Offset)) + DataExtractor StrData = Form == DW_FORM_line_strp + ? C->getLineStringExtractor() + : U ? U->getStringExtractor() + : C->getStringExtractor(); + if (const char *Str = StrData.getCStr(&Offset)) return Str; - return None; + std::string Msg = FormEncodingString(Form).str(); + if (Index) + Msg += (" uses index " + Twine(*Index) + ", but the referenced string").str(); + Msg += (" offset " + Twine(Offset) + " is beyond .debug_str bounds").str(); + return make_error(Msg, + inconvertibleErrorCode()); } Optional DWARFFormValue::getAsAddress() const { diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index 82c34f537036..eed0a60ec75e 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -214,13 +214,17 @@ DWARFUnit::getAddrOffsetSectionItem(uint32_t Index) const { return {{Address, Section}}; } -Optional DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { +Expected DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { if (!StringOffsetsTableContribution) - return None; + return make_error( + "DW_FORM_strx used without a valid string offsets table", + inconvertibleErrorCode()); unsigned ItemSize = getDwarfStringOffsetsByteSize(); uint64_t Offset = getStringOffsetsBase() + Index * ItemSize; if (StringOffsetSection.Data.size() < Offset + ItemSize) - return None; + return make_error("DW_FORM_strx uses index " + Twine(Index) + + ", which is too large", + inconvertibleErrorCode()); DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection, isLittleEndian, 0); return DA.getRelocatedValue(ItemSize, &Offset); @@ -603,7 +607,7 @@ bool DWARFUnit::parseDWO() { DWO->setAddrOffsetSection(AddrOffsetSection, *AddrOffsetSectionBase); if (getVersion() == 4) { auto DWORangesBase = UnitDie.getRangesBaseAttribute(); - DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0); + DWO->setRangesSection(RangeSection, DWORangesBase.getValueOr(0)); } return true; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index 7673a721c4ea..6424c2f59844 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -390,6 +390,9 @@ bool DWARFVerifier::handleDebugInfo() { OS << "Verifying non-dwo Units...\n"; NumErrors += verifyUnits(DCtx.getNormalUnitsVector()); + + OS << "Verifying dwo Units...\n"; + NumErrors += verifyUnits(DCtx.getDWOUnitsVector()); return NumErrors == 0; } @@ -400,10 +403,13 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, if (!Die.isValid()) return NumErrors; + DWARFUnit *Unit = Die.getDwarfUnit(); + auto RangesOrError = Die.getAddressRanges(); if (!RangesOrError) { // FIXME: Report the error. - ++NumErrors; + if (!Unit->isDWOUnit()) + ++NumErrors; llvm::consumeError(RangesOrError.takeError()); return NumErrors; } @@ -496,15 +502,18 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, }; const DWARFObject &DObj = DCtx.getDWARFObj(); + DWARFUnit *U = Die.getDwarfUnit(); const auto Attr = AttrValue.Attr; switch (Attr) { case DW_AT_ranges: // Make sure the offset in the DW_AT_ranges attribute is valid. if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - unsigned DwarfVersion = Die.getDwarfUnit()->getVersion(); + unsigned DwarfVersion = U->getVersion(); const DWARFSection &RangeSection = DwarfVersion < 5 ? DObj.getRangesSection() : DObj.getRnglistsSection(); + if (U->isDWOUnit() && RangeSection.Data.empty()) + break; if (*SectionOffset >= RangeSection.Data.size()) ReportError( "DW_AT_ranges offset is beyond " + @@ -517,7 +526,7 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, case DW_AT_stmt_list: // Make sure the offset in the DW_AT_stmt_list attribute is valid. if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - if (*SectionOffset >= DObj.getLineSection().Data.size()) + if (*SectionOffset >= U->getLineSection().Data.size()) ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " + llvm::formatv("{0:x8}", *SectionOffset)); break; @@ -525,9 +534,18 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, ReportError("DIE has invalid DW_AT_stmt_list encoding:"); break; case DW_AT_location: { + // FIXME: It might be nice if there's a way to walk location expressions + // without trying to resolve the address ranges - it'd be a more efficient + // API (since the API is currently unnecessarily resolving addresses for + // this use case which only wants to validate the expressions themselves) & + // then the expressions could be validated even if the addresses can't be + // resolved. + // That sort of API would probably look like a callback "for each + // expression" with some way to lazily resolve the address ranges when + // needed (& then the existing API used here could be built on top of that - + // using the callback API to build the data structure and return it). if (Expected> Loc = Die.getLocations(DW_AT_location)) { - DWARFUnit *U = Die.getDwarfUnit(); for (const auto &Entry : *Loc) { DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0); DWARFExpression Expression(Data, U->getAddressByteSize(), @@ -539,8 +557,12 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, if (Error || !Expression.verify(U)) ReportError("DIE contains invalid DWARF expression:"); } - } else - ReportError(toString(Loc.takeError())); + } else if (Error Err = handleErrors( + Loc.takeError(), [&](std::unique_ptr E) { + return U->isDWOUnit() ? Error::success() + : Error(std::move(E)); + })) + ReportError(toString(std::move(Err))); break; } case DW_AT_specification: @@ -576,7 +598,8 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, case DW_AT_call_file: case DW_AT_decl_file: { if (auto FileIdx = AttrValue.Value.getAsUnsignedConstant()) { - DWARFUnit *U = Die.getDwarfUnit(); + if (U->isDWOUnit() && !U->isTypeUnit()) + break; const auto *LT = U->getContext().getLineTableForUnit(U); if (LT) { if (!LT->hasFileAtIndex(*FileIdx)) { @@ -616,7 +639,6 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue, ReferenceMap &LocalReferences, ReferenceMap &CrossUnitReferences) { - const DWARFObject &DObj = DCtx.getDWARFObj(); auto DieCU = Die.getDwarfUnit(); unsigned NumErrors = 0; const auto Form = AttrValue.Value.getForm(); @@ -667,51 +689,15 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, } break; } - case DW_FORM_strp: { - auto SecOffset = AttrValue.Value.getAsSectionOffset(); - assert(SecOffset); // DW_FORM_strp is a section offset. - if (SecOffset && *SecOffset >= DObj.getStrSection().size()) { - ++NumErrors; - error() << "DW_FORM_strp offset beyond .debug_str bounds:\n"; - dump(Die) << '\n'; - } - break; - } + case DW_FORM_strp: case DW_FORM_strx: case DW_FORM_strx1: case DW_FORM_strx2: case DW_FORM_strx3: case DW_FORM_strx4: { - auto Index = AttrValue.Value.getRawUValue(); - auto DieCU = Die.getDwarfUnit(); - // Check that we have a valid DWARF v5 string offsets table. - if (!DieCU->getStringOffsetsTableContribution()) { - ++NumErrors; - error() << FormEncodingString(Form) - << " used without a valid string offsets table:\n"; - dump(Die) << '\n'; - break; - } - // Check that the index is within the bounds of the section. - unsigned ItemSize = DieCU->getDwarfStringOffsetsByteSize(); - // Use a 64-bit type to calculate the offset to guard against overflow. - uint64_t Offset = - (uint64_t)DieCU->getStringOffsetsBase() + Index * ItemSize; - if (DObj.getStrOffsetsSection().Data.size() < Offset + ItemSize) { - ++NumErrors; - error() << FormEncodingString(Form) << " uses index " - << format("%" PRIu64, Index) << ", which is too large:\n"; - dump(Die) << '\n'; - break; - } - // Check that the string offset is valid. - uint64_t StringOffset = *DieCU->getStringOffsetSectionItem(Index); - if (StringOffset >= DObj.getStrSection().size()) { + if (Error E = AttrValue.Value.getAsCString().takeError()) { ++NumErrors; - error() << FormEncodingString(Form) << " uses index " - << format("%" PRIu64, Index) - << ", but the referenced string" - " offset is beyond .debug_str bounds:\n"; + error() << toString(std::move(E)) << ":\n"; dump(Die) << '\n'; } break; diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp index b2c43b893cd3..6eef6f84ab40 100644 --- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp +++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp @@ -531,7 +531,7 @@ llvm::Error DwarfTransformer::verify(StringRef GsymPath) { << LR->Locations.size() << "\n"; Log << " " << NumDwarfInlineInfos << " DWARF frames:\n"; for (size_t Idx = 0; Idx < NumDwarfInlineInfos; ++Idx) { - const auto dii = DwarfInlineInfos.getFrame(Idx); + const auto &dii = DwarfInlineInfos.getFrame(Idx); Log << " [" << Idx << "]: " << dii.FunctionName << " @ " << dii.FileName << ':' << dii.Line << '\n'; } @@ -551,7 +551,7 @@ llvm::Error DwarfTransformer::verify(StringRef GsymPath) { ++Idx) { const auto &gii = LR->Locations[Idx]; if (Idx < NumDwarfInlineInfos) { - const auto dii = DwarfInlineInfos.getFrame(Idx); + const auto &dii = DwarfInlineInfos.getFrame(Idx); gsymFilename = LR->getSourceFile(Idx); // Verify function name if (dii.FunctionName.find(gii.Name.str()) != 0) diff --git a/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp b/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp index 1a92e2cb7754..f9a763d724a8 100644 --- a/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp +++ b/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp @@ -343,15 +343,25 @@ Expected MSFBuilder::commit(StringRef Path, Layout = std::move(*L); uint64_t FileSize = uint64_t(Layout.SB->BlockSize) * Layout.SB->NumBlocks; - if (FileSize > UINT32_MAX) { - // FIXME: Changing the BinaryStream classes to use 64-bit numbers lets - // us create PDBs larger than 4 GiB successfully. The file format is - // block-based and as long as each stream is small enough, PDBs larger than - // 4 GiB might work. Check if tools can handle these large PDBs, and if so - // add support for writing them. + // Ensure that the file size is under the limit for the specified block size. + if (FileSize > getMaxFileSizeFromBlockSize(Layout.SB->BlockSize)) { + msf_error_code error_code = [](uint32_t BlockSize) { + switch (BlockSize) { + case 8192: + return msf_error_code::size_overflow_8192; + case 16384: + return msf_error_code::size_overflow_16384; + case 32768: + return msf_error_code::size_overflow_32768; + default: + return msf_error_code::size_overflow_4096; + } + }(Layout.SB->BlockSize); + return make_error( - msf_error_code::size_overflow, - formatv("File size would have been {0,1:N}", FileSize)); + error_code, + formatv("File size {0,1:N} too large for current PDB page size {1}", + FileSize, Layout.SB->BlockSize)); } auto OutFileOrError = FileOutputBuffer::create(Path, FileSize); diff --git a/llvm/lib/DebugInfo/MSF/MSFError.cpp b/llvm/lib/DebugInfo/MSF/MSFError.cpp index e42157e9d48e..9df2158423a4 100644 --- a/llvm/lib/DebugInfo/MSF/MSFError.cpp +++ b/llvm/lib/DebugInfo/MSF/MSFError.cpp @@ -28,8 +28,14 @@ public: case msf_error_code::insufficient_buffer: return "The buffer is not large enough to read the requested number of " "bytes."; - case msf_error_code::size_overflow: + case msf_error_code::size_overflow_4096: return "Output data is larger than 4 GiB."; + case msf_error_code::size_overflow_8192: + return "Output data is larger than 8 GiB."; + case msf_error_code::size_overflow_16384: + return "Output data is larger than 16 GiB."; + case msf_error_code::size_overflow_32768: + return "Output data is larger than 32 GiB."; case msf_error_code::not_writable: return "The specified stream is not writable."; case msf_error_code::no_stream: diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp index cde645236851..5c61530c470d 100644 --- a/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -100,7 +100,7 @@ PDBFile::getStreamBlockList(uint32_t StreamIndex) const { return ContainerLayout.StreamMap[StreamIndex]; } -uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); } +uint64_t PDBFile::getFileSize() const { return Buffer->getLength(); } Expected> PDBFile::getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const { diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp index fd9a0deb54d6..f9e67014477e 100644 --- a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp @@ -518,8 +518,8 @@ SymbolCache::findLineTable(uint16_t Modi) const { const std::vector &RHS) { return LHS[0].Addr < RHS[0].Addr; }); - for (size_t I = 0; I < EntryList.size(); ++I) - llvm::append_range(ModuleLineTable, EntryList[I]); + for (std::vector &I : EntryList) + llvm::append_range(ModuleLineTable, I); return ModuleLineTable; } diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp index f3f09584fdc9..5ec79df17fed 100644 --- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp +++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -20,6 +20,7 @@ #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBContext.h" +#include "llvm/Debuginfod/Debuginfod.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Object/COFF.h" #include "llvm/Object/MachO.h" @@ -384,7 +385,14 @@ bool findDebugBinary(const std::vector &DebugFileDirectory, } } } - return false; + // Try debuginfod client cache and known servers. + Expected PathOrErr = getCachedOrDownloadDebuginfo(BuildID); + if (!PathOrErr) { + consumeError(PathOrErr.takeError()); + return false; + } + Result = *PathOrErr; + return true; } } // end anonymous namespace diff --git a/llvm/lib/Debuginfod/Debuginfod.cpp b/llvm/lib/Debuginfod/Debuginfod.cpp new file mode 100644 index 000000000000..389b18fd62ac --- /dev/null +++ b/llvm/lib/Debuginfod/Debuginfod.cpp @@ -0,0 +1,183 @@ +//===-- llvm/Debuginfod/Debuginfod.cpp - Debuginfod client library --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file defines the fetchInfo function, which retrieves +/// any of the three supported artifact types: (executable, debuginfo, source +/// file) associated with a build-id from debuginfod servers. If a source file +/// is to be fetched, its absolute path must be specified in the Description +/// argument to fetchInfo. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Debuginfod/Debuginfod.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Debuginfod/HTTPClient.h" +#include "llvm/Support/CachePruning.h" +#include "llvm/Support/Caching.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/xxhash.h" + +namespace llvm { +static std::string uniqueKey(llvm::StringRef S) { return utostr(xxHash64(S)); } + +// Returns a binary BuildID as a normalized hex string. +// Uses lowercase for compatibility with common debuginfod servers. +static std::string buildIDToString(BuildIDRef ID) { + return llvm::toHex(ID, /*LowerCase=*/true); +} + +Expected> getDefaultDebuginfodUrls() { + const char *DebuginfodUrlsEnv = std::getenv("DEBUGINFOD_URLS"); + if (DebuginfodUrlsEnv == NULL) + return SmallVector(); + + SmallVector DebuginfodUrls; + StringRef(DebuginfodUrlsEnv).split(DebuginfodUrls, " "); + return DebuginfodUrls; +} + +Expected getDefaultDebuginfodCacheDirectory() { + if (const char *CacheDirectoryEnv = std::getenv("DEBUGINFOD_CACHE_PATH")) + return CacheDirectoryEnv; + + SmallString<64> CacheDirectory; + if (!sys::path::cache_directory(CacheDirectory)) + return createStringError( + errc::io_error, "Unable to determine appropriate cache directory."); + return std::string(CacheDirectory); +} + +std::chrono::milliseconds getDefaultDebuginfodTimeout() { + long Timeout; + const char *DebuginfodTimeoutEnv = std::getenv("DEBUGINFOD_TIMEOUT"); + if (DebuginfodTimeoutEnv && + to_integer(StringRef(DebuginfodTimeoutEnv).trim(), Timeout, 10)) + return std::chrono::milliseconds(Timeout * 1000); + + return std::chrono::milliseconds(90 * 1000); +} + +/// The following functions fetch a debuginfod artifact to a file in a local +/// cache and return the cached file path. They first search the local cache, +/// followed by the debuginfod servers. + +Expected getCachedOrDownloadSource(BuildIDRef ID, + StringRef SourceFilePath) { + SmallString<64> UrlPath; + sys::path::append(UrlPath, sys::path::Style::posix, "buildid", + buildIDToString(ID), "source", + sys::path::convert_to_slash(SourceFilePath)); + return getCachedOrDownloadArtifact(uniqueKey(UrlPath), UrlPath); +} + +Expected getCachedOrDownloadExecutable(BuildIDRef ID) { + SmallString<64> UrlPath; + sys::path::append(UrlPath, sys::path::Style::posix, "buildid", + buildIDToString(ID), "executable"); + return getCachedOrDownloadArtifact(uniqueKey(UrlPath), UrlPath); +} + +Expected getCachedOrDownloadDebuginfo(BuildIDRef ID) { + SmallString<64> UrlPath; + sys::path::append(UrlPath, sys::path::Style::posix, "buildid", + buildIDToString(ID), "debuginfo"); + return getCachedOrDownloadArtifact(uniqueKey(UrlPath), UrlPath); +} + +// General fetching function. +Expected getCachedOrDownloadArtifact(StringRef UniqueKey, + StringRef UrlPath) { + SmallString<10> CacheDir; + + Expected CacheDirOrErr = getDefaultDebuginfodCacheDirectory(); + if (!CacheDirOrErr) + return CacheDirOrErr.takeError(); + CacheDir = *CacheDirOrErr; + + Expected> DebuginfodUrlsOrErr = + getDefaultDebuginfodUrls(); + if (!DebuginfodUrlsOrErr) + return DebuginfodUrlsOrErr.takeError(); + SmallVector &DebuginfodUrls = *DebuginfodUrlsOrErr; + return getCachedOrDownloadArtifact(UniqueKey, UrlPath, CacheDir, + DebuginfodUrls, + getDefaultDebuginfodTimeout()); +} + +Expected getCachedOrDownloadArtifact( + StringRef UniqueKey, StringRef UrlPath, StringRef CacheDirectoryPath, + ArrayRef DebuginfodUrls, std::chrono::milliseconds Timeout) { + SmallString<64> AbsCachedArtifactPath; + sys::path::append(AbsCachedArtifactPath, CacheDirectoryPath, + "llvmcache-" + UniqueKey); + + Expected CacheOrErr = + localCache("Debuginfod-client", ".debuginfod-client", CacheDirectoryPath); + if (!CacheOrErr) + return CacheOrErr.takeError(); + + FileCache Cache = *CacheOrErr; + // We choose an arbitrary Task parameter as we do not make use of it. + unsigned Task = 0; + Expected CacheAddStreamOrErr = Cache(Task, UniqueKey); + if (!CacheAddStreamOrErr) + return CacheAddStreamOrErr.takeError(); + AddStreamFn &CacheAddStream = *CacheAddStreamOrErr; + if (!CacheAddStream) + return std::string(AbsCachedArtifactPath); + // The artifact was not found in the local cache, query the debuginfod + // servers. + if (!HTTPClient::isAvailable()) + return createStringError(errc::io_error, + "No working HTTP client is available."); + + if (!HTTPClient::IsInitialized) + return createStringError( + errc::io_error, + "A working HTTP client is available, but it is not initialized. To " + "allow Debuginfod to make HTTP requests, call HTTPClient::initialize() " + "at the beginning of main."); + + HTTPClient Client; + Client.setTimeout(Timeout); + for (StringRef ServerUrl : DebuginfodUrls) { + SmallString<64> ArtifactUrl; + sys::path::append(ArtifactUrl, sys::path::Style::posix, ServerUrl, UrlPath); + + Expected ResponseOrErr = Client.get(ArtifactUrl); + if (!ResponseOrErr) + return ResponseOrErr.takeError(); + + HTTPResponseBuffer &Response = *ResponseOrErr; + if (Response.Code != 200) + continue; + + // We have retrieved the artifact from this server, and now add it to the + // file cache. + Expected> FileStreamOrErr = + CacheAddStream(Task); + if (!FileStreamOrErr) + return FileStreamOrErr.takeError(); + std::unique_ptr &FileStream = *FileStreamOrErr; + if (!Response.Body) + return createStringError( + errc::io_error, "Unallocated MemoryBuffer in HTTPResponseBuffer."); + + *FileStream->OS << StringRef(Response.Body->getBufferStart(), + Response.Body->getBufferSize()); + + // Return the path to the artifact on disk. + return std::string(AbsCachedArtifactPath); + } + + return createStringError(errc::argument_out_of_domain, "build id not found"); +} +} // namespace llvm diff --git a/llvm/lib/Debuginfod/HTTPClient.cpp b/llvm/lib/Debuginfod/HTTPClient.cpp new file mode 100644 index 000000000000..65f457933b92 --- /dev/null +++ b/llvm/lib/Debuginfod/HTTPClient.cpp @@ -0,0 +1,216 @@ +//===-- llvm/Debuginfod/HTTPClient.cpp - HTTP client library ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file defines the methods of the HTTPRequest, HTTPClient, and +/// BufferedHTTPResponseHandler classes. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Debuginfod/HTTPClient.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" +#ifdef LLVM_ENABLE_CURL +#include +#endif + +using namespace llvm; + +HTTPRequest::HTTPRequest(StringRef Url) { this->Url = Url.str(); } + +bool operator==(const HTTPRequest &A, const HTTPRequest &B) { + return A.Url == B.Url && A.Method == B.Method && + A.FollowRedirects == B.FollowRedirects; +} + +HTTPResponseHandler::~HTTPResponseHandler() = default; + +static inline bool parseContentLengthHeader(StringRef LineRef, + size_t &ContentLength) { + // Content-Length is a mandatory header, and the only one we handle. + return LineRef.consume_front("Content-Length: ") && + to_integer(LineRef.trim(), ContentLength, 10); +} + +Error BufferedHTTPResponseHandler::handleHeaderLine(StringRef HeaderLine) { + if (ResponseBuffer.Body) + return Error::success(); + + size_t ContentLength; + if (parseContentLengthHeader(HeaderLine, ContentLength)) + ResponseBuffer.Body = + WritableMemoryBuffer::getNewUninitMemBuffer(ContentLength); + + return Error::success(); +} + +Error BufferedHTTPResponseHandler::handleBodyChunk(StringRef BodyChunk) { + if (!ResponseBuffer.Body) + return createStringError(errc::io_error, + "Unallocated response buffer. HTTP Body data " + "received before Content-Length header."); + if (Offset + BodyChunk.size() > ResponseBuffer.Body->getBufferSize()) + return createStringError(errc::io_error, + "Content size exceeds buffer size."); + memcpy(ResponseBuffer.Body->getBufferStart() + Offset, BodyChunk.data(), + BodyChunk.size()); + Offset += BodyChunk.size(); + return Error::success(); +} + +Error BufferedHTTPResponseHandler::handleStatusCode(unsigned Code) { + ResponseBuffer.Code = Code; + return Error::success(); +} + +bool HTTPClient::IsInitialized = false; + +class HTTPClientCleanup { +public: + ~HTTPClientCleanup() { HTTPClient::cleanup(); } +}; +static const HTTPClientCleanup Cleanup; + +Expected HTTPClient::perform(const HTTPRequest &Request) { + BufferedHTTPResponseHandler Handler; + if (Error Err = perform(Request, Handler)) + return std::move(Err); + return std::move(Handler.ResponseBuffer); +} + +Expected HTTPClient::get(StringRef Url) { + HTTPRequest Request(Url); + return perform(Request); +} + +#ifdef LLVM_ENABLE_CURL + +bool HTTPClient::isAvailable() { return true; } + +void HTTPClient::initialize() { + if (!IsInitialized) { + curl_global_init(CURL_GLOBAL_ALL); + IsInitialized = true; + } +} + +void HTTPClient::cleanup() { + if (IsInitialized) { + curl_global_cleanup(); + IsInitialized = false; + } +} + +void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) { + if (Timeout < std::chrono::milliseconds(0)) + Timeout = std::chrono::milliseconds(0); + curl_easy_setopt(Curl, CURLOPT_TIMEOUT_MS, Timeout.count()); +} + +/// CurlHTTPRequest and the curl{Header,Write}Function are implementation +/// details used to work with Curl. Curl makes callbacks with a single +/// customizable pointer parameter. +struct CurlHTTPRequest { + CurlHTTPRequest(HTTPResponseHandler &Handler) : Handler(Handler) {} + void storeError(Error Err) { + ErrorState = joinErrors(std::move(Err), std::move(ErrorState)); + } + HTTPResponseHandler &Handler; + llvm::Error ErrorState = Error::success(); +}; + +static size_t curlHeaderFunction(char *Contents, size_t Size, size_t NMemb, + CurlHTTPRequest *CurlRequest) { + assert(Size == 1 && "The Size passed by libCURL to CURLOPT_HEADERFUNCTION " + "should always be 1."); + if (Error Err = + CurlRequest->Handler.handleHeaderLine(StringRef(Contents, NMemb))) { + CurlRequest->storeError(std::move(Err)); + return 0; + } + return NMemb; +} + +static size_t curlWriteFunction(char *Contents, size_t Size, size_t NMemb, + CurlHTTPRequest *CurlRequest) { + Size *= NMemb; + if (Error Err = + CurlRequest->Handler.handleBodyChunk(StringRef(Contents, Size))) { + CurlRequest->storeError(std::move(Err)); + return 0; + } + return Size; +} + +HTTPClient::HTTPClient() { + assert(IsInitialized && + "Must call HTTPClient::initialize() at the beginning of main()."); + if (Curl) + return; + assert((Curl = curl_easy_init()) && "Curl could not be initialized."); + // Set the callback hooks. + curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, curlWriteFunction); + curl_easy_setopt(Curl, CURLOPT_HEADERFUNCTION, curlHeaderFunction); +} + +HTTPClient::~HTTPClient() { curl_easy_cleanup(Curl); } + +Error HTTPClient::perform(const HTTPRequest &Request, + HTTPResponseHandler &Handler) { + if (Request.Method != HTTPMethod::GET) + return createStringError(errc::invalid_argument, + "Unsupported CURL request method."); + + SmallString<128> Url = Request.Url; + curl_easy_setopt(Curl, CURLOPT_URL, Url.c_str()); + curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, Request.FollowRedirects); + + CurlHTTPRequest CurlRequest(Handler); + curl_easy_setopt(Curl, CURLOPT_WRITEDATA, &CurlRequest); + curl_easy_setopt(Curl, CURLOPT_HEADERDATA, &CurlRequest); + CURLcode CurlRes = curl_easy_perform(Curl); + if (CurlRes != CURLE_OK) + return joinErrors(std::move(CurlRequest.ErrorState), + createStringError(errc::io_error, + "curl_easy_perform() failed: %s\n", + curl_easy_strerror(CurlRes))); + if (CurlRequest.ErrorState) + return std::move(CurlRequest.ErrorState); + + unsigned Code; + curl_easy_getinfo(Curl, CURLINFO_RESPONSE_CODE, &Code); + if (Error Err = Handler.handleStatusCode(Code)) + return joinErrors(std::move(CurlRequest.ErrorState), std::move(Err)); + + return std::move(CurlRequest.ErrorState); +} + +#else + +HTTPClient::HTTPClient() = default; + +HTTPClient::~HTTPClient() = default; + +bool HTTPClient::isAvailable() { return false; } + +void HTTPClient::initialize() {} + +void HTTPClient::cleanup() {} + +void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {} + +Error HTTPClient::perform(const HTTPRequest &Request, + HTTPResponseHandler &Handler) { + llvm_unreachable("No HTTP Client implementation available."); +} + +#endif diff --git a/llvm/lib/Demangle/DLangDemangle.cpp b/llvm/lib/Demangle/DLangDemangle.cpp index f380aa90035e..0cefbd63a7ae 100644 --- a/llvm/lib/Demangle/DLangDemangle.cpp +++ b/llvm/lib/Demangle/DLangDemangle.cpp @@ -242,11 +242,77 @@ const char *Demangler::parseIdentifier(OutputBuffer *Demangled, // TODO: Parse template instances with a length prefix. + // There can be multiple different declarations in the same function that + // have the same mangled name. To make the mangled names unique, a fake + // parent in the form `__Sddd' is added to the symbol. + if (Len >= 4 && Mangled[0] == '_' && Mangled[1] == '_' && Mangled[2] == 'S') { + const char *NumPtr = Mangled + 3; + while (NumPtr < (Mangled + Len) && std::isdigit(*NumPtr)) + ++NumPtr; + + if (Mangled + Len == NumPtr) { + // Skip over the fake parent. + Mangled += Len; + return parseIdentifier(Demangled, Mangled); + } + + // Else demangle it as a plain identifier. + } + return parseLName(Demangled, Mangled, Len); } const char *Demangler::parseLName(OutputBuffer *Demangled, const char *Mangled, unsigned long Len) { + switch (Len) { + case 6: + if (strncmp(Mangled, "__initZ", Len + 1) == 0) { + // The static initializer for a given symbol. + Demangled->prepend("initializer for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + if (strncmp(Mangled, "__vtblZ", Len + 1) == 0) { + // The vtable symbol for a given class. + Demangled->prepend("vtable for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 7: + if (strncmp(Mangled, "__ClassZ", Len + 1) == 0) { + // The classinfo symbol for a given class. + Demangled->prepend("ClassInfo for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 11: + if (strncmp(Mangled, "__InterfaceZ", Len + 1) == 0) { + // The interface symbol for a given class. + Demangled->prepend("Interface for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 12: + if (strncmp(Mangled, "__ModuleInfoZ", Len + 1) == 0) { + // The ModuleInfo symbol for a given module. + Demangled->prepend("ModuleInfo for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + } + *Demangled << StringView(Mangled, Len); Mangled += Len; diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp index 3ea9ffee6554..27d8833ae19e 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp @@ -241,7 +241,9 @@ private: } case Branch32: { Kind = x86_64::BranchPCRel32; - Addend = 0; + // BranchPCRel32 implicitly handles the '-4' PC adjustment, so we have to + // adjust the addend by '+4' to compensate. + Addend += 4; break; } } @@ -252,7 +254,7 @@ private: Edge GE(Kind, Offset, *GraphSymbol, Addend); LLVM_DEBUG({ dbgs() << " "; - printEdge(dbgs(), *BlockToFix, GE, getELFX86RelocationKindName(Kind)); + printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind)); dbgs() << "\n"; }); diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp index 200f42aec067..ed912280ac82 100644 --- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -170,8 +170,8 @@ std::unique_ptr MCJIT::emitObject(Module *M) { PM.run(*M); // Flush the output buffer to get the generated code into memory - std::unique_ptr CompiledObjBuffer( - new SmallVectorMemoryBuffer(std::move(ObjBufferSV))); + auto CompiledObjBuffer = std::make_unique( + std::move(ObjBufferSV), /*RequiresNullTerminator=*/false); // If we have an object cache, tell it about the new object. // Note that we're using the compiled image, not the loaded image (as below). diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h index 52e7eda90310..a5dd420c9132 100644 --- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -151,12 +151,8 @@ class MCJIT : public ExecutionEngine { } void markAllLoadedModulesAsFinalized() { - for (ModulePtrSet::iterator I = LoadedModules.begin(), - E = LoadedModules.end(); - I != E; ++I) { - Module *M = *I; + for (Module *M : LoadedModules) FinalizedModules.insert(M); - } LoadedModules.clear(); } @@ -167,10 +163,8 @@ class MCJIT : public ExecutionEngine { void freeModulePtrSet(ModulePtrSet& MPS) { // Go through the module set and delete everything. - for (ModulePtrSet::iterator I = MPS.begin(), E = MPS.end(); I != E; ++I) { - Module *M = *I; + for (Module *M : MPS) delete M; - } MPS.clear(); } }; diff --git a/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp b/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp index 9ff6cec8c6c5..e2a0cadb6348 100644 --- a/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp @@ -78,11 +78,10 @@ public: : IRMaterializationUnit(ES, MO, std::move(TSM)), Parent(Parent) {} PartitioningIRMaterializationUnit( - ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags, - SymbolStringPtr InitSymbol, SymbolNameToDefinitionMap SymbolToDefinition, + ThreadSafeModule TSM, Interface I, + SymbolNameToDefinitionMap SymbolToDefinition, CompileOnDemandLayer &Parent) - : IRMaterializationUnit(std::move(TSM), std::move(SymbolFlags), - std::move(InitSymbol), + : IRMaterializationUnit(std::move(TSM), std::move(I), std::move(SymbolToDefinition)), Parent(Parent) {} @@ -298,7 +297,9 @@ void CompileOnDemandLayer::emitPartition( if (GVsToExtract->empty()) { if (auto Err = R->replace(std::make_unique( - std::move(TSM), R->getSymbols(), R->getInitializerSymbol(), + std::move(TSM), + MaterializationUnit::Interface(R->getSymbols(), + R->getInitializerSymbol()), std::move(Defs), *this))) { getExecutionSession().reportError(std::move(Err)); R->failMaterialization(); diff --git a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp index f8efed15edea..f34247005258 100644 --- a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp @@ -53,7 +53,8 @@ Expected SimpleCompiler::operator()(Module &M) { } auto ObjBuffer = std::make_unique( - std::move(ObjBufferSV), M.getModuleIdentifier() + "-jitted-objectbuffer"); + std::move(ObjBufferSV), M.getModuleIdentifier() + "-jitted-objectbuffer", + /*RequiresNullTerminator=*/false); auto Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp index 56a97f83d915..aa82cf38c45d 100644 --- a/llvm/lib/ExecutionEngine/Orc/Core.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp @@ -243,8 +243,7 @@ void AsynchronousSymbolQuery::detach() { AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit( SymbolMap Symbols) - : MaterializationUnit(extractFlags(Symbols), nullptr), - Symbols(std::move(Symbols)) {} + : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {} StringRef AbsoluteSymbolsMaterializationUnit::getName() const { return ""; @@ -263,18 +262,18 @@ void AbsoluteSymbolsMaterializationUnit::discard(const JITDylib &JD, Symbols.erase(Name); } -SymbolFlagsMap +MaterializationUnit::Interface AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) { SymbolFlagsMap Flags; for (const auto &KV : Symbols) Flags[KV.first] = KV.second.getFlags(); - return Flags; + return MaterializationUnit::Interface(std::move(Flags), nullptr); } ReExportsMaterializationUnit::ReExportsMaterializationUnit( JITDylib *SourceJD, JITDylibLookupFlags SourceJDLookupFlags, SymbolAliasMap Aliases) - : MaterializationUnit(extractFlags(Aliases), nullptr), SourceJD(SourceJD), + : MaterializationUnit(extractFlags(Aliases)), SourceJD(SourceJD), SourceJDLookupFlags(SourceJDLookupFlags), Aliases(std::move(Aliases)) {} StringRef ReExportsMaterializationUnit::getName() const { @@ -456,13 +455,13 @@ void ReExportsMaterializationUnit::discard(const JITDylib &JD, Aliases.erase(Name); } -SymbolFlagsMap +MaterializationUnit::Interface ReExportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { SymbolFlagsMap SymbolFlags; for (auto &KV : Aliases) SymbolFlags[KV.first] = KV.second.AliasFlags; - return SymbolFlags; + return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr); } Expected buildSimpleReexportsAliasMap(JITDylib &SourceJD, @@ -2492,10 +2491,19 @@ void ExecutionSession::OL_applyQueryPhase1( } } - // If we get here then we've moved on to the next JITDylib. - LLVM_DEBUG(dbgs() << "Phase 1 moving to next JITDylib.\n"); - ++IPLS->CurSearchOrderIndex; - IPLS->NewJITDylib = true; + if (IPLS->DefGeneratorCandidates.empty() && + IPLS->DefGeneratorNonCandidates.empty()) { + // Early out if there are no remaining symbols. + LLVM_DEBUG(dbgs() << "All symbols matched.\n"); + IPLS->CurSearchOrderIndex = IPLS->SearchOrder.size(); + break; + } else { + // If we get here then we've moved on to the next JITDylib with candidates + // remaining. + LLVM_DEBUG(dbgs() << "Phase 1 moving to next JITDylib.\n"); + ++IPLS->CurSearchOrderIndex; + IPLS->NewJITDylib = true; + } } // Remove any weakly referenced candidates that could not be found/generated. diff --git a/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp index 8479495623b8..fe62138c790c 100644 --- a/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp +++ b/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp @@ -154,8 +154,24 @@ public: } DebugSecInfos.push_back({&Sec, Sec.getName().substr(0, SepPos), Sec.getName().substr(SepPos + 1), 0, 0}); - } else + } else { NonDebugSections.push_back(&Sec); + + // If the first block in the section has a non-zero alignment offset + // then we need to add a padding block, since the section command in + // the header doesn't allow for aligment offsets. + SectionRange R(Sec); + if (!R.empty()) { + auto &FB = *R.getFirstBlock(); + if (FB.getAlignmentOffset() != 0) { + auto Padding = G.allocateBuffer(FB.getAlignmentOffset()); + memset(Padding.data(), 0, Padding.size()); + G.createContentBlock(Sec, Padding, + FB.getAddress() - FB.getAlignmentOffset(), + FB.getAlignment(), 0); + } + } + } } // Create container block. diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp index b17d196f01b6..eded54f4bfb3 100644 --- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp @@ -28,8 +28,8 @@ class DSOHandleMaterializationUnit : public MaterializationUnit { public: DSOHandleMaterializationUnit(ELFNixPlatform &ENP, const SymbolStringPtr &DSOHandleSymbol) - : MaterializationUnit(createDSOHandleSectionSymbols(ENP, DSOHandleSymbol), - DSOHandleSymbol), + : MaterializationUnit( + createDSOHandleSectionInterface(ENP, DSOHandleSymbol)), ENP(ENP) {} StringRef getName() const override { return "DSOHandleMU"; } @@ -70,12 +70,13 @@ public: void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} private: - static SymbolFlagsMap - createDSOHandleSectionSymbols(ELFNixPlatform &ENP, - const SymbolStringPtr &DSOHandleSymbol) { + static MaterializationUnit::Interface + createDSOHandleSectionInterface(ELFNixPlatform &ENP, + const SymbolStringPtr &DSOHandleSymbol) { SymbolFlagsMap SymbolFlags; SymbolFlags[DSOHandleSymbol] = JITSymbolFlags::Exported; - return SymbolFlags; + return MaterializationUnit::Interface(std::move(SymbolFlags), + DSOHandleSymbol); } ArrayRef getDSOHandleContent(size_t PointerSize) { diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp index 2ab9ed4f856b..ae2d47fb8c5e 100644 --- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp @@ -8,6 +8,7 @@ #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/Layer.h" +#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" @@ -269,25 +270,30 @@ Error DynamicLibrarySearchGenerator::tryToGenerate( } Expected> -StaticLibraryDefinitionGenerator::Load(ObjectLayer &L, const char *FileName) { +StaticLibraryDefinitionGenerator::Load( + ObjectLayer &L, const char *FileName, + GetObjectFileInterface GetObjFileInterface) { auto ArchiveBuffer = errorOrToExpected(MemoryBuffer::getFile(FileName)); if (!ArchiveBuffer) return ArchiveBuffer.takeError(); - return Create(L, std::move(*ArchiveBuffer)); + return Create(L, std::move(*ArchiveBuffer), std::move(GetObjFileInterface)); } Expected> -StaticLibraryDefinitionGenerator::Load(ObjectLayer &L, const char *FileName, - const Triple &TT) { +StaticLibraryDefinitionGenerator::Load( + ObjectLayer &L, const char *FileName, const Triple &TT, + GetObjectFileInterface GetObjFileInterface) { + auto B = object::createBinary(FileName); if (!B) return B.takeError(); // If this is a regular archive then create an instance from it. if (isa(B->getBinary())) - return Create(L, std::move(B->takeBinary().second)); + return Create(L, std::move(B->takeBinary().second), + std::move(GetObjFileInterface)); // If this is a universal binary then search for a slice matching the given // Triple. @@ -309,7 +315,8 @@ StaticLibraryDefinitionGenerator::Load(ObjectLayer &L, const char *FileName, " .. " + formatv("{0:x}", Obj.getOffset() + Obj.getSize()) + ": " + SliceBuffer.getError().message(), SliceBuffer.getError()); - return Create(L, std::move(*SliceBuffer)); + return Create(L, std::move(*SliceBuffer), + std::move(GetObjFileInterface)); } } @@ -326,11 +333,13 @@ StaticLibraryDefinitionGenerator::Load(ObjectLayer &L, const char *FileName, Expected> StaticLibraryDefinitionGenerator::Create( - ObjectLayer &L, std::unique_ptr ArchiveBuffer) { + ObjectLayer &L, std::unique_ptr ArchiveBuffer, + GetObjectFileInterface GetObjFileInterface) { Error Err = Error::success(); std::unique_ptr ADG( - new StaticLibraryDefinitionGenerator(L, std::move(ArchiveBuffer), Err)); + new StaticLibraryDefinitionGenerator( + L, std::move(ArchiveBuffer), std::move(GetObjFileInterface), Err)); if (Err) return std::move(Err); @@ -371,7 +380,12 @@ Error StaticLibraryDefinitionGenerator::tryToGenerate( MemoryBufferRef ChildBufferRef(ChildBufferInfo.first, ChildBufferInfo.second); - if (auto Err = L.add(JD, MemoryBuffer::getMemBuffer(ChildBufferRef, false))) + auto I = GetObjFileInterface(L.getExecutionSession(), ChildBufferRef); + if (!I) + return I.takeError(); + + if (auto Err = L.add(JD, MemoryBuffer::getMemBuffer(ChildBufferRef, false), + std::move(*I))) return Err; } @@ -379,9 +393,15 @@ Error StaticLibraryDefinitionGenerator::tryToGenerate( } StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator( - ObjectLayer &L, std::unique_ptr ArchiveBuffer, Error &Err) - : L(L), ArchiveBuffer(std::move(ArchiveBuffer)), - Archive(std::make_unique(*this->ArchiveBuffer, Err)) {} + ObjectLayer &L, std::unique_ptr ArchiveBuffer, + GetObjectFileInterface GetObjFileInterface, Error &Err) + : L(L), GetObjFileInterface(std::move(GetObjFileInterface)), + ArchiveBuffer(std::move(ArchiveBuffer)), + Archive(std::make_unique(*this->ArchiveBuffer, Err)) { + + if (!this->GetObjFileInterface) + this->GetObjFileInterface = getObjectFileInterface; +} } // End namespace orc. } // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp index ee1630a2ffa8..f427271bb45d 100644 --- a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp @@ -31,8 +31,8 @@ public: CompileCallbackMaterializationUnit(SymbolStringPtr Name, CompileFunction Compile) - : MaterializationUnit(SymbolFlagsMap({{Name, JITSymbolFlags::Exported}}), - nullptr), + : MaterializationUnit(Interface( + SymbolFlagsMap({{Name, JITSymbolFlags::Exported}}), nullptr)), Name(std::move(Name)), Compile(std::move(Compile)) {} StringRef getName() const override { return ""; } diff --git a/llvm/lib/ExecutionEngine/Orc/Layer.cpp b/llvm/lib/ExecutionEngine/Orc/Layer.cpp index 20dfba23bf10..adb8861793b1 100644 --- a/llvm/lib/ExecutionEngine/Orc/Layer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Layer.cpp @@ -10,9 +10,8 @@ #include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" #include "llvm/IR/Constants.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE "orc" @@ -33,7 +32,7 @@ Error IRLayer::add(ResourceTrackerSP RT, ThreadSafeModule TSM) { IRMaterializationUnit::IRMaterializationUnit( ExecutionSession &ES, const IRSymbolMapper::ManglingOptions &MO, ThreadSafeModule TSM) - : MaterializationUnit(SymbolFlagsMap(), nullptr), TSM(std::move(TSM)) { + : MaterializationUnit(Interface()), TSM(std::move(TSM)) { assert(this->TSM && "Module must not be null"); @@ -98,10 +97,10 @@ IRMaterializationUnit::IRMaterializationUnit( } IRMaterializationUnit::IRMaterializationUnit( - ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags, - SymbolStringPtr InitSymbol, SymbolNameToDefinitionMap SymbolToDefinition) - : MaterializationUnit(std::move(SymbolFlags), std::move(InitSymbol)), - TSM(std::move(TSM)), SymbolToDefinition(std::move(SymbolToDefinition)) {} + ThreadSafeModule TSM, Interface I, + SymbolNameToDefinitionMap SymbolToDefinition) + : MaterializationUnit(std::move(I)), TSM(std::move(TSM)), + SymbolToDefinition(std::move(SymbolToDefinition)) {} StringRef IRMaterializationUnit::getName() const { if (TSM) @@ -161,37 +160,47 @@ ObjectLayer::ObjectLayer(ExecutionSession &ES) : ES(ES) {} ObjectLayer::~ObjectLayer() {} -Error ObjectLayer::add(ResourceTrackerSP RT, std::unique_ptr O) { +Error ObjectLayer::add(ResourceTrackerSP RT, std::unique_ptr O, + MaterializationUnit::Interface I) { assert(RT && "RT can not be null"); - auto ObjMU = BasicObjectLayerMaterializationUnit::Create(*this, std::move(O)); - if (!ObjMU) - return ObjMU.takeError(); auto &JD = RT->getJITDylib(); - return JD.define(std::move(*ObjMU), std::move(RT)); + return JD.define(std::make_unique( + *this, std::move(O), std::move(I)), + std::move(RT)); +} + +Error ObjectLayer::add(ResourceTrackerSP RT, std::unique_ptr O) { + auto I = getObjectFileInterface(getExecutionSession(), O->getMemBufferRef()); + if (!I) + return I.takeError(); + return add(std::move(RT), std::move(O), std::move(*I)); +} + +Error ObjectLayer::add(JITDylib &JD, std::unique_ptr O) { + auto I = getObjectFileInterface(getExecutionSession(), O->getMemBufferRef()); + if (!I) + return I.takeError(); + return add(JD, std::move(O), std::move(*I)); } Expected> BasicObjectLayerMaterializationUnit::Create(ObjectLayer &L, std::unique_ptr O) { - auto ObjSymInfo = - getObjectSymbolInfo(L.getExecutionSession(), O->getMemBufferRef()); - if (!ObjSymInfo) - return ObjSymInfo.takeError(); + auto ObjInterface = + getObjectFileInterface(L.getExecutionSession(), O->getMemBufferRef()); - auto &SymbolFlags = ObjSymInfo->first; - auto &InitSymbol = ObjSymInfo->second; + if (!ObjInterface) + return ObjInterface.takeError(); return std::unique_ptr( - new BasicObjectLayerMaterializationUnit( - L, std::move(O), std::move(SymbolFlags), std::move(InitSymbol))); + new BasicObjectLayerMaterializationUnit(L, std::move(O), + std::move(*ObjInterface))); } BasicObjectLayerMaterializationUnit::BasicObjectLayerMaterializationUnit( - ObjectLayer &L, std::unique_ptr O, SymbolFlagsMap SymbolFlags, - SymbolStringPtr InitSymbol) - : MaterializationUnit(std::move(SymbolFlags), std::move(InitSymbol)), L(L), - O(std::move(O)) {} + ObjectLayer &L, std::unique_ptr O, Interface I) + : MaterializationUnit(std::move(I)), L(L), O(std::move(O)) {} StringRef BasicObjectLayerMaterializationUnit::getName() const { if (O) diff --git a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp index e1f494415e86..66453e6a632f 100644 --- a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp @@ -144,7 +144,7 @@ createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit( LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc) - : MaterializationUnit(extractFlags(CallableAliases), nullptr), + : MaterializationUnit(extractFlags(CallableAliases)), LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD), CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {} @@ -219,7 +219,7 @@ void LazyReexportsMaterializationUnit::discard(const JITDylib &JD, CallableAliases.erase(Name); } -SymbolFlagsMap +MaterializationUnit::Interface LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { SymbolFlagsMap SymbolFlags; for (auto &KV : Aliases) { @@ -227,7 +227,7 @@ LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { "Lazy re-exports must be callable symbols"); SymbolFlags[KV.first] = KV.second.AliasFlags; } - return SymbolFlags; + return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr); } } // End namespace orc. diff --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp index 46c915dfea9e..fb2e90e1c9c5 100644 --- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp @@ -28,8 +28,7 @@ class MachOHeaderMaterializationUnit : public MaterializationUnit { public: MachOHeaderMaterializationUnit(MachOPlatform &MOP, const SymbolStringPtr &HeaderStartSymbol) - : MaterializationUnit(createHeaderSymbols(MOP, HeaderStartSymbol), - HeaderStartSymbol), + : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)), MOP(MOP) {} StringRef getName() const override { return "MachOHeaderMU"; } @@ -110,9 +109,9 @@ private: return G.createContentBlock(HeaderSection, HeaderContent, 0, 8, 0); } - static SymbolFlagsMap - createHeaderSymbols(MachOPlatform &MOP, - const SymbolStringPtr &HeaderStartSymbol) { + static MaterializationUnit::Interface + createHeaderInterface(MachOPlatform &MOP, + const SymbolStringPtr &HeaderStartSymbol) { SymbolFlagsMap HeaderSymbolFlags; HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported; @@ -120,7 +119,8 @@ private: HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] = JITSymbolFlags::Exported; - return HeaderSymbolFlags; + return MaterializationUnit::Interface(std::move(HeaderSymbolFlags), + HeaderStartSymbol); } MachOPlatform &MOP; diff --git a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp index 7b21e6a684ca..9c243c9bf1d2 100644 --- a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp @@ -7,13 +7,8 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/Mangling.h" -#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h" -#include "llvm/ExecutionEngine/Orc/MachOPlatform.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Mangler.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE "orc" @@ -85,188 +80,5 @@ void IRSymbolMapper::add(ExecutionSession &ES, const ManglingOptions &MO, } } -static SymbolStringPtr addInitSymbol(SymbolFlagsMap &SymbolFlags, - ExecutionSession &ES, - StringRef ObjFileName) { - SymbolStringPtr InitSymbol; - size_t Counter = 0; - - do { - std::string InitSymString; - raw_string_ostream(InitSymString) - << "$." << ObjFileName << ".__inits." << Counter++; - InitSymbol = ES.intern(InitSymString); - } while (SymbolFlags.count(InitSymbol)); - - SymbolFlags[InitSymbol] = JITSymbolFlags::MaterializationSideEffectsOnly; - return InitSymbol; -} - -static Expected> -getMachOObjectFileSymbolInfo(ExecutionSession &ES, - const object::MachOObjectFile &Obj) { - SymbolFlagsMap SymbolFlags; - - for (auto &Sym : Obj.symbols()) { - Expected SymFlagsOrErr = Sym.getFlags(); - if (!SymFlagsOrErr) - // TODO: Test this error. - return SymFlagsOrErr.takeError(); - - // Skip symbols not defined in this object file. - if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) - continue; - - // Skip symbols that are not global. - if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) - continue; - - // Skip symbols that have type SF_File. - if (auto SymType = Sym.getType()) { - if (*SymType == object::SymbolRef::ST_File) - continue; - } else - return SymType.takeError(); - - auto Name = Sym.getName(); - if (!Name) - return Name.takeError(); - auto InternedName = ES.intern(*Name); - auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); - if (!SymFlags) - return SymFlags.takeError(); - - // Strip the 'exported' flag from MachO linker-private symbols. - if (Name->startswith("l")) - *SymFlags &= ~JITSymbolFlags::Exported; - - SymbolFlags[InternedName] = std::move(*SymFlags); - } - - SymbolStringPtr InitSymbol; - for (auto &Sec : Obj.sections()) { - auto SecType = Obj.getSectionType(Sec); - if ((SecType & MachO::SECTION_TYPE) == MachO::S_MOD_INIT_FUNC_POINTERS) { - InitSymbol = addInitSymbol(SymbolFlags, ES, Obj.getFileName()); - break; - } - auto SegName = Obj.getSectionFinalSegmentName(Sec.getRawDataRefImpl()); - auto SecName = cantFail(Obj.getSectionName(Sec.getRawDataRefImpl())); - if (MachOPlatform::isInitializerSection(SegName, SecName)) { - InitSymbol = addInitSymbol(SymbolFlags, ES, Obj.getFileName()); - break; - } - } - - return std::make_pair(std::move(SymbolFlags), std::move(InitSymbol)); -} - -static Expected> -getELFObjectFileSymbolInfo(ExecutionSession &ES, - const object::ELFObjectFileBase &Obj) { - SymbolFlagsMap SymbolFlags; - for (auto &Sym : Obj.symbols()) { - Expected SymFlagsOrErr = Sym.getFlags(); - if (!SymFlagsOrErr) - // TODO: Test this error. - return SymFlagsOrErr.takeError(); - - // Skip symbols not defined in this object file. - if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) - continue; - - // Skip symbols that are not global. - if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) - continue; - - // Skip symbols that have type SF_File. - if (auto SymType = Sym.getType()) { - if (*SymType == object::SymbolRef::ST_File) - continue; - } else - return SymType.takeError(); - - auto Name = Sym.getName(); - if (!Name) - return Name.takeError(); - auto InternedName = ES.intern(*Name); - auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); - if (!SymFlags) - return SymFlags.takeError(); - - // ELF STB_GNU_UNIQUE should map to Weak for ORC. - if (Sym.getBinding() == ELF::STB_GNU_UNIQUE) - *SymFlags |= JITSymbolFlags::Weak; - - SymbolFlags[InternedName] = std::move(*SymFlags); - } - - SymbolStringPtr InitSymbol; - for (auto &Sec : Obj.sections()) { - if (auto SecName = Sec.getName()) { - if (ELFNixPlatform::isInitializerSection(*SecName)) { - InitSymbol = addInitSymbol(SymbolFlags, ES, Obj.getFileName()); - break; - } - } - } - - return std::make_pair(std::move(SymbolFlags), InitSymbol); -} - -Expected> -getGenericObjectFileSymbolInfo(ExecutionSession &ES, - const object::ObjectFile &Obj) { - SymbolFlagsMap SymbolFlags; - for (auto &Sym : Obj.symbols()) { - Expected SymFlagsOrErr = Sym.getFlags(); - if (!SymFlagsOrErr) - // TODO: Test this error. - return SymFlagsOrErr.takeError(); - - // Skip symbols not defined in this object file. - if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) - continue; - - // Skip symbols that are not global. - if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) - continue; - - // Skip symbols that have type SF_File. - if (auto SymType = Sym.getType()) { - if (*SymType == object::SymbolRef::ST_File) - continue; - } else - return SymType.takeError(); - - auto Name = Sym.getName(); - if (!Name) - return Name.takeError(); - auto InternedName = ES.intern(*Name); - auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); - if (!SymFlags) - return SymFlags.takeError(); - - SymbolFlags[InternedName] = std::move(*SymFlags); - } - - return std::make_pair(std::move(SymbolFlags), nullptr); -} - -Expected> -getObjectSymbolInfo(ExecutionSession &ES, MemoryBufferRef ObjBuffer) { - auto Obj = object::ObjectFile::createObjectFile(ObjBuffer); - - if (!Obj) - return Obj.takeError(); - - if (auto *MachOObj = dyn_cast(Obj->get())) - return getMachOObjectFileSymbolInfo(ES, *MachOObj); - else if (auto *ELFObj = dyn_cast(Obj->get())) - return getELFObjectFileSymbolInfo(ES, *ELFObj); - - return getGenericObjectFileSymbolInfo(ES, **Obj); -} - } // End namespace orc. } // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp new file mode 100644 index 000000000000..c1ad569dd65d --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp @@ -0,0 +1,205 @@ +//===------ ObjectFileInterface.cpp - MU interface utils for objects ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" +#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h" +#include "llvm/ExecutionEngine/Orc/MachOPlatform.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "orc" + +namespace llvm { +namespace orc { + +void addInitSymbol(MaterializationUnit::Interface &I, ExecutionSession &ES, + StringRef ObjFileName) { + assert(!I.InitSymbol && "I already has an init symbol"); + size_t Counter = 0; + + do { + std::string InitSymString; + raw_string_ostream(InitSymString) + << "$." << ObjFileName << ".__inits." << Counter++; + I.InitSymbol = ES.intern(InitSymString); + } while (I.SymbolFlags.count(I.InitSymbol)); + + I.SymbolFlags[I.InitSymbol] = JITSymbolFlags::MaterializationSideEffectsOnly; +} + +static Expected +getMachOObjectFileSymbolInfo(ExecutionSession &ES, + const object::MachOObjectFile &Obj) { + MaterializationUnit::Interface I; + + for (auto &Sym : Obj.symbols()) { + Expected SymFlagsOrErr = Sym.getFlags(); + if (!SymFlagsOrErr) + // TODO: Test this error. + return SymFlagsOrErr.takeError(); + + // Skip symbols not defined in this object file. + if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) + continue; + + // Skip symbols that are not global. + if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) + continue; + + // Skip symbols that have type SF_File. + if (auto SymType = Sym.getType()) { + if (*SymType == object::SymbolRef::ST_File) + continue; + } else + return SymType.takeError(); + + auto Name = Sym.getName(); + if (!Name) + return Name.takeError(); + auto InternedName = ES.intern(*Name); + auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); + if (!SymFlags) + return SymFlags.takeError(); + + // Strip the 'exported' flag from MachO linker-private symbols. + if (Name->startswith("l")) + *SymFlags &= ~JITSymbolFlags::Exported; + + I.SymbolFlags[InternedName] = std::move(*SymFlags); + } + + for (auto &Sec : Obj.sections()) { + auto SecType = Obj.getSectionType(Sec); + if ((SecType & MachO::SECTION_TYPE) == MachO::S_MOD_INIT_FUNC_POINTERS) { + addInitSymbol(I, ES, Obj.getFileName()); + break; + } + auto SegName = Obj.getSectionFinalSegmentName(Sec.getRawDataRefImpl()); + auto SecName = cantFail(Obj.getSectionName(Sec.getRawDataRefImpl())); + if (MachOPlatform::isInitializerSection(SegName, SecName)) { + addInitSymbol(I, ES, Obj.getFileName()); + break; + } + } + + return I; +} + +static Expected +getELFObjectFileSymbolInfo(ExecutionSession &ES, + const object::ELFObjectFileBase &Obj) { + MaterializationUnit::Interface I; + + for (auto &Sym : Obj.symbols()) { + Expected SymFlagsOrErr = Sym.getFlags(); + if (!SymFlagsOrErr) + // TODO: Test this error. + return SymFlagsOrErr.takeError(); + + // Skip symbols not defined in this object file. + if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) + continue; + + // Skip symbols that are not global. + if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) + continue; + + // Skip symbols that have type SF_File. + if (auto SymType = Sym.getType()) { + if (*SymType == object::SymbolRef::ST_File) + continue; + } else + return SymType.takeError(); + + auto Name = Sym.getName(); + if (!Name) + return Name.takeError(); + auto InternedName = ES.intern(*Name); + auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); + if (!SymFlags) + return SymFlags.takeError(); + + // ELF STB_GNU_UNIQUE should map to Weak for ORC. + if (Sym.getBinding() == ELF::STB_GNU_UNIQUE) + *SymFlags |= JITSymbolFlags::Weak; + + I.SymbolFlags[InternedName] = std::move(*SymFlags); + } + + SymbolStringPtr InitSymbol; + for (auto &Sec : Obj.sections()) { + if (auto SecName = Sec.getName()) { + if (ELFNixPlatform::isInitializerSection(*SecName)) { + addInitSymbol(I, ES, Obj.getFileName()); + break; + } + } + } + + return I; +} + +Expected +getGenericObjectFileSymbolInfo(ExecutionSession &ES, + const object::ObjectFile &Obj) { + MaterializationUnit::Interface I; + + for (auto &Sym : Obj.symbols()) { + Expected SymFlagsOrErr = Sym.getFlags(); + if (!SymFlagsOrErr) + // TODO: Test this error. + return SymFlagsOrErr.takeError(); + + // Skip symbols not defined in this object file. + if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) + continue; + + // Skip symbols that are not global. + if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) + continue; + + // Skip symbols that have type SF_File. + if (auto SymType = Sym.getType()) { + if (*SymType == object::SymbolRef::ST_File) + continue; + } else + return SymType.takeError(); + + auto Name = Sym.getName(); + if (!Name) + return Name.takeError(); + auto InternedName = ES.intern(*Name); + auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); + if (!SymFlags) + return SymFlags.takeError(); + + I.SymbolFlags[InternedName] = std::move(*SymFlags); + } + + return I; +} + +Expected +getObjectFileInterface(ExecutionSession &ES, MemoryBufferRef ObjBuffer) { + auto Obj = object::ObjectFile::createObjectFile(ObjBuffer); + + if (!Obj) + return Obj.takeError(); + + if (auto *MachOObj = dyn_cast(Obj->get())) + return getMachOObjectFileSymbolInfo(ES, *MachOObj); + else if (auto *ELFObj = dyn_cast(Obj->get())) + return getELFObjectFileSymbolInfo(ES, *ELFObj); + + return getGenericObjectFileSymbolInfo(ES, **Obj); +} + +} // End namespace orc. +} // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index 6f840a079dd1..0d6a33c5685e 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -23,12 +23,6 @@ using namespace llvm::orc; namespace { class LinkGraphMaterializationUnit : public MaterializationUnit { -private: - struct LinkGraphInterface { - SymbolFlagsMap SymbolFlags; - SymbolStringPtr InitSymbol; - }; - public: static std::unique_ptr Create(ObjectLinkingLayer &ObjLinkingLayer, std::unique_ptr G) { @@ -44,9 +38,9 @@ public: } private: - static LinkGraphInterface scanLinkGraph(ExecutionSession &ES, LinkGraph &G) { + static Interface scanLinkGraph(ExecutionSession &ES, LinkGraph &G) { - LinkGraphInterface LGI; + Interface LGI; for (auto *Sym : G.defined_symbols()) { // Skip local symbols. @@ -98,11 +92,9 @@ private: } LinkGraphMaterializationUnit(ObjectLinkingLayer &ObjLinkingLayer, - std::unique_ptr G, - LinkGraphInterface LGI) - : MaterializationUnit(std::move(LGI.SymbolFlags), - std::move(LGI.InitSymbol)), - ObjLinkingLayer(ObjLinkingLayer), G(std::move(G)) {} + std::unique_ptr G, Interface LGI) + : MaterializationUnit(std::move(LGI)), ObjLinkingLayer(ObjLinkingLayer), + G(std::move(G)) {} void discard(const JITDylib &JD, const SymbolStringPtr &Name) override { for (auto *Sym : G->defined_symbols()) @@ -257,7 +249,8 @@ public: { - // Check that InternedResult matches up with MR->getSymbols(). + // Check that InternedResult matches up with MR->getSymbols(), overriding + // flags if requested. // This guards against faulty transformations / compilers / object caches. // First check that there aren't any missing symbols. @@ -266,16 +259,20 @@ public: SymbolNameVector MissingSymbols; for (auto &KV : MR->getSymbols()) { + auto I = InternedResult.find(KV.first); + // If this is a materialization-side-effects only symbol then bump // the counter and make sure it's *not* defined, otherwise make // sure that it is defined. if (KV.second.hasMaterializationSideEffectsOnly()) { ++NumMaterializationSideEffectsOnlySymbols; - if (InternedResult.count(KV.first)) + if (I != InternedResult.end()) ExtraSymbols.push_back(KV.first); continue; - } else if (!InternedResult.count(KV.first)) + } else if (I == InternedResult.end()) MissingSymbols.push_back(KV.first); + else if (Layer.OverrideObjectFlags) + I->second.setFlags(KV.second); } // If there were missing symbols then report the error. diff --git a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp index 673f7394450f..77a8f5af8ba0 100644 --- a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp +++ b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp @@ -192,8 +192,8 @@ public: LLVMOrcMaterializationUnitMaterializeFunction Materialize, LLVMOrcMaterializationUnitDiscardFunction Discard, LLVMOrcMaterializationUnitDestroyFunction Destroy) - : llvm::orc::MaterializationUnit(std::move(InitialSymbolFlags), - std::move(InitSymbol)), + : llvm::orc::MaterializationUnit( + Interface(std::move(InitialSymbolFlags), std::move(InitSymbol))), Name(std::move(Name)), Ctx(Ctx), Materialize(Materialize), Discard(Discard), Destroy(Destroy) {} diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index f16c6bdbfa4f..3f38d26869d4 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -124,8 +124,10 @@ void RuntimeDyldImpl::resolveRelocations() { std::lock_guard locked(lock); // Print out the sections prior to relocation. - LLVM_DEBUG(for (int i = 0, e = Sections.size(); i != e; ++i) - dumpSectionMemory(Sections[i], "before relocations");); + LLVM_DEBUG({ + for (SectionEntry &S : Sections) + dumpSectionMemory(S, "before relocations"); + }); // First, resolve relocations associated with external symbols. if (auto Err = resolveExternalSymbols()) { @@ -136,21 +138,23 @@ void RuntimeDyldImpl::resolveRelocations() { resolveLocalRelocations(); // Print out sections after relocation. - LLVM_DEBUG(for (int i = 0, e = Sections.size(); i != e; ++i) - dumpSectionMemory(Sections[i], "after relocations");); + LLVM_DEBUG({ + for (SectionEntry &S : Sections) + dumpSectionMemory(S, "after relocations"); + }); } void RuntimeDyldImpl::resolveLocalRelocations() { // Iterate over all outstanding relocations - for (auto it = Relocations.begin(), e = Relocations.end(); it != e; ++it) { + for (const auto &Rel : Relocations) { // The Section here (Sections[i]) refers to the section in which the // symbol for the relocation is located. The SectionID in the relocation // entry provides the section to which the relocation will be applied. - unsigned Idx = it->first; + unsigned Idx = Rel.first; uint64_t Addr = getSectionLoadAddress(Idx); LLVM_DEBUG(dbgs() << "Resolving relocations Section #" << Idx << "\t" << format("%p", (uintptr_t)Addr) << "\n"); - resolveRelocationList(it->second, Addr); + resolveRelocationList(Rel.second, Addr); } Relocations.clear(); } @@ -457,9 +461,9 @@ static uint64_t computeAllocationSizeForSections(std::vector &SectionSizes, uint64_t Alignment) { uint64_t TotalSize = 0; - for (size_t Idx = 0, Cnt = SectionSizes.size(); Idx < Cnt; Idx++) { + for (uint64_t SectionSize : SectionSizes) { uint64_t AlignedSize = - (SectionSizes[Idx] + Alignment - 1) / Alignment * Alignment; + (SectionSize + Alignment - 1) / Alignment * Alignment; TotalSize += AlignedSize; } return TotalSize; diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp index 18f1a2314853..5157d51fd18c 100644 --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -996,7 +996,7 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createSections( Builder.SetInsertPoint(AllocaIP.getBlock()->getTerminator()); AllocaIP = Builder.saveIP(); InsertPointTy AfterIP = - applyStaticWorkshareLoop(Loc.DL, LoopInfo, AllocaIP, true); + applyStaticWorkshareLoop(Loc.DL, LoopInfo, AllocaIP, !IsNowait); BasicBlock *LoopAfterBB = AfterIP.getBlock(); Instruction *SplitPos = LoopAfterBB->getTerminator(); if (!isa_and_nonnull(SplitPos)) @@ -1156,7 +1156,7 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createReductions( Builder.SetInsertPoint(NonAtomicRedBlock); for (auto En : enumerate(ReductionInfos)) { const ReductionInfo &RI = En.value(); - Type *ValueType = RI.getElementType(); + Type *ValueType = RI.ElementType; Value *RedValue = Builder.CreateLoad(ValueType, RI.Variable, "red.value." + Twine(En.index())); Value *PrivateRedValue = @@ -1181,8 +1181,8 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createReductions( Builder.SetInsertPoint(AtomicRedBlock); if (CanGenerateAtomic) { for (const ReductionInfo &RI : ReductionInfos) { - Builder.restoreIP(RI.AtomicReductionGen(Builder.saveIP(), RI.Variable, - RI.PrivateVariable)); + Builder.restoreIP(RI.AtomicReductionGen(Builder.saveIP(), RI.ElementType, + RI.Variable, RI.PrivateVariable)); if (!Builder.GetInsertBlock()) return InsertPointTy(); } @@ -1207,13 +1207,13 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createReductions( RedArrayTy, LHSArrayPtr, 0, En.index()); Value *LHSI8Ptr = Builder.CreateLoad(Builder.getInt8PtrTy(), LHSI8PtrPtr); Value *LHSPtr = Builder.CreateBitCast(LHSI8Ptr, RI.Variable->getType()); - Value *LHS = Builder.CreateLoad(RI.getElementType(), LHSPtr); + Value *LHS = Builder.CreateLoad(RI.ElementType, LHSPtr); Value *RHSI8PtrPtr = Builder.CreateConstInBoundsGEP2_64( RedArrayTy, RHSArrayPtr, 0, En.index()); Value *RHSI8Ptr = Builder.CreateLoad(Builder.getInt8PtrTy(), RHSI8PtrPtr); Value *RHSPtr = Builder.CreateBitCast(RHSI8Ptr, RI.PrivateVariable->getType()); - Value *RHS = Builder.CreateLoad(RI.getElementType(), RHSPtr); + Value *RHS = Builder.CreateLoad(RI.ElementType, RHSPtr); Value *Reduced; Builder.restoreIP(RI.ReductionGen(Builder.saveIP(), LHS, RHS, Reduced)); if (!Builder.GetInsertBlock()) @@ -1329,13 +1329,10 @@ CanonicalLoopInfo *OpenMPIRBuilder::createLoopSkeleton( LoopInfos.emplace_front(); CanonicalLoopInfo *CL = &LoopInfos.front(); - CL->Preheader = Preheader; CL->Header = Header; CL->Cond = Cond; - CL->Body = Body; CL->Latch = Latch; CL->Exit = Exit; - CL->After = After; #ifndef NDEBUG CL->assertOK(); @@ -1359,7 +1356,7 @@ OpenMPIRBuilder::createCanonicalLoop(const LocationDescription &Loc, // Split the loop at the insertion point: Branch to the preheader and move // every following instruction to after the loop (the After BB). Also, the // new successor is the loop's after block. - Builder.CreateBr(CL->Preheader); + Builder.CreateBr(CL->getPreheader()); After->getInstList().splice(After->begin(), BB->getInstList(), Builder.GetInsertPoint(), BB->end()); After->replaceSuccessorsPhiUsesWith(BB, After); @@ -1791,6 +1788,12 @@ OpenMPIRBuilder::collapseLoops(DebugLoc DL, ArrayRef Loops, BasicBlock *OrigAfter = Outermost->getAfter(); Function *F = OrigPreheader->getParent(); + // Loop control blocks that may become orphaned later. + SmallVector OldControlBBs; + OldControlBBs.reserve(6 * Loops.size()); + for (CanonicalLoopInfo *Loop : Loops) + Loop->collectControlBlocks(OldControlBBs); + // Setup the IRBuilder for inserting the trip count computation. Builder.SetCurrentDebugLocation(DL); if (ComputeIP.isSet()) @@ -1828,7 +1831,7 @@ OpenMPIRBuilder::collapseLoops(DebugLoc DL, ArrayRef Loops, Value *Leftover = Result->getIndVar(); SmallVector NewIndVars; - NewIndVars.set_size(NumLoops); + NewIndVars.resize(NumLoops); for (int i = NumLoops - 1; i >= 1; --i) { Value *OrigTripCount = Loops[i]->getTripCount(); @@ -1886,10 +1889,6 @@ OpenMPIRBuilder::collapseLoops(DebugLoc DL, ArrayRef Loops, Loops[i]->getIndVar()->replaceAllUsesWith(NewIndVars[i]); // Remove unused parts of the input loops. - SmallVector OldControlBBs; - OldControlBBs.reserve(6 * Loops.size()); - for (CanonicalLoopInfo *Loop : Loops) - Loop->collectControlBlocks(OldControlBBs); removeUnusedBlocksFromParent(OldControlBBs); for (CanonicalLoopInfo *L : Loops) @@ -1915,6 +1914,12 @@ OpenMPIRBuilder::tileLoops(DebugLoc DL, ArrayRef Loops, BasicBlock *InnerEnter = InnermostLoop->getBody(); BasicBlock *InnerLatch = InnermostLoop->getLatch(); + // Loop control blocks that may become orphaned later. + SmallVector OldControlBBs; + OldControlBBs.reserve(6 * Loops.size()); + for (CanonicalLoopInfo *Loop : Loops) + Loop->collectControlBlocks(OldControlBBs); + // Collect original trip counts and induction variable to be accessible by // index. Also, the structure of the original loops is not preserved during // the construction of the tiled loops, so do it before we scavenge the BBs of @@ -2074,10 +2079,6 @@ OpenMPIRBuilder::tileLoops(DebugLoc DL, ArrayRef Loops, } // Remove unused parts of the original loops. - SmallVector OldControlBBs; - OldControlBBs.reserve(6 * Loops.size()); - for (CanonicalLoopInfo *Loop : Loops) - Loop->collectControlBlocks(OldControlBBs); removeUnusedBlocksFromParent(OldControlBBs); for (CanonicalLoopInfo *L : Loops) @@ -3079,7 +3080,7 @@ OpenMPIRBuilder::createAtomicWrite(const LocationDescription &Loc, OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicUpdate( const LocationDescription &Loc, Instruction *AllocIP, AtomicOpValue &X, Value *Expr, AtomicOrdering AO, AtomicRMWInst::BinOp RMWOp, - AtomicUpdateCallbackTy &UpdateOp, bool IsXLHSInRHSPart) { + AtomicUpdateCallbackTy &UpdateOp, bool IsXBinopExpr) { if (!updateToLocation(Loc)) return Loc.IP; @@ -3097,7 +3098,7 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicUpdate( }); emitAtomicUpdate(AllocIP, X.Var, Expr, AO, RMWOp, UpdateOp, X.IsVolatile, - IsXLHSInRHSPart); + IsXBinopExpr); checkAndEmitFlushAfterAtomic(Loc, AO, AtomicKind::Update); return Builder.saveIP(); } @@ -3134,13 +3135,13 @@ std::pair OpenMPIRBuilder::emitAtomicUpdate(Instruction *AllocIP, Value *X, Value *Expr, AtomicOrdering AO, AtomicRMWInst::BinOp RMWOp, AtomicUpdateCallbackTy &UpdateOp, - bool VolatileX, bool IsXLHSInRHSPart) { + bool VolatileX, bool IsXBinopExpr) { Type *XElemTy = X->getType()->getPointerElementType(); bool DoCmpExch = ((RMWOp == AtomicRMWInst::BAD_BINOP) || (RMWOp == AtomicRMWInst::FAdd)) || (RMWOp == AtomicRMWInst::FSub) || - (RMWOp == AtomicRMWInst::Sub && !IsXLHSInRHSPart); + (RMWOp == AtomicRMWInst::Sub && !IsXBinopExpr); std::pair Res; if (XElemTy->isIntegerTy() && !DoCmpExch) { @@ -3232,7 +3233,7 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicCapture( const LocationDescription &Loc, Instruction *AllocIP, AtomicOpValue &X, AtomicOpValue &V, Value *Expr, AtomicOrdering AO, AtomicRMWInst::BinOp RMWOp, AtomicUpdateCallbackTy &UpdateOp, - bool UpdateExpr, bool IsPostfixUpdate, bool IsXLHSInRHSPart) { + bool UpdateExpr, bool IsPostfixUpdate, bool IsXBinopExpr) { if (!updateToLocation(Loc)) return Loc.IP; @@ -3251,9 +3252,8 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicCapture( // If UpdateExpr is 'x' updated with some `expr` not based on 'x', // 'x' is simply atomically rewritten with 'expr'. AtomicRMWInst::BinOp AtomicOp = (UpdateExpr ? RMWOp : AtomicRMWInst::Xchg); - std::pair Result = - emitAtomicUpdate(AllocIP, X.Var, Expr, AO, AtomicOp, UpdateOp, - X.IsVolatile, IsXLHSInRHSPart); + std::pair Result = emitAtomicUpdate( + AllocIP, X.Var, Expr, AO, AtomicOp, UpdateOp, X.IsVolatile, IsXBinopExpr); Value *CapturedVal = (IsPostfixUpdate ? Result.first : Result.second); Builder.CreateStore(CapturedVal, V.Var, V.IsVolatile); @@ -3321,7 +3321,16 @@ void CanonicalLoopInfo::collectControlBlocks( // flow. For consistency, this also means we do not add the Body block, which // is just the entry to the body code. BBs.reserve(BBs.size() + 6); - BBs.append({Preheader, Header, Cond, Latch, Exit, After}); + BBs.append({getPreheader(), Header, Cond, Latch, Exit, getAfter()}); +} + +BasicBlock *CanonicalLoopInfo::getPreheader() const { + assert(isValid() && "Requires a valid canonical loop"); + for (BasicBlock *Pred : predecessors(Header)) { + if (Pred != Latch) + return Pred; + } + llvm_unreachable("Missing preheader"); } void CanonicalLoopInfo::assertOK() const { @@ -3330,6 +3339,10 @@ void CanonicalLoopInfo::assertOK() const { if (!isValid()) return; + BasicBlock *Preheader = getPreheader(); + BasicBlock *Body = getBody(); + BasicBlock *After = getAfter(); + // Verify standard control-flow we use for OpenMP loops. assert(Preheader); assert(isa(Preheader->getTerminator()) && @@ -3415,11 +3428,8 @@ void CanonicalLoopInfo::assertOK() const { } void CanonicalLoopInfo::invalidate() { - Preheader = nullptr; Header = nullptr; Cond = nullptr; - Body = nullptr; Latch = nullptr; Exit = nullptr; - After = nullptr; } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index c9748e1387eb..bbe0c97e60a2 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -512,10 +512,8 @@ void TypePrinting::incorporateTypes() { // the unnamed ones out to a numbering and remove the anonymous structs. unsigned NextNumber = 0; - std::vector::iterator NextToUse = NamedTypes.begin(), I, E; - for (I = NamedTypes.begin(), E = NamedTypes.end(); I != E; ++I) { - StructType *STy = *I; - + std::vector::iterator NextToUse = NamedTypes.begin(); + for (StructType *STy : NamedTypes) { // Ignore anonymous types. if (STy->isLiteral()) continue; @@ -1450,6 +1448,12 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, return; } + if (const auto *NC = dyn_cast(CV)) { + Out << "no_cfi "; + WriteAsOperandInternal(Out, NC->getGlobalValue(), WriterCtx); + return; + } + if (const ConstantArray *CA = dyn_cast(CV)) { Type *ETy = CA->getType()->getElementType(); Out << '['; @@ -1583,11 +1587,9 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, Out << ", "; } - if (CE->hasIndices()) { - ArrayRef Indices = CE->getIndices(); - for (unsigned i = 0, e = Indices.size(); i != e; ++i) - Out << ", " << Indices[i]; - } + if (CE->hasIndices()) + for (unsigned I : CE->getIndices()) + Out << ", " << I; if (CE->isCast()) { Out << " to "; @@ -3528,8 +3530,8 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) { } maybePrintComdat(Out, *GV); - if (GV->getAlignment()) - Out << ", align " << GV->getAlignment(); + if (MaybeAlign A = GV->getAlign()) + Out << ", align " << A->value(); SmallVector, 4> MDs; GV->getAllMetadata(MDs); @@ -3637,13 +3639,13 @@ void AssemblyWriter::printTypeIdentities() { } auto &NamedTypes = TypePrinter.getNamedTypes(); - for (unsigned I = 0, E = NamedTypes.size(); I != E; ++I) { - PrintLLVMName(Out, NamedTypes[I]->getName(), LocalPrefix); + for (StructType *NamedType : NamedTypes) { + PrintLLVMName(Out, NamedType->getName(), LocalPrefix); Out << " = type "; // Make sure we print out at least one level of the type structure, so // that we do not get %FILE = type %FILE - TypePrinter.printStructBody(NamedTypes[I], Out); + TypePrinter.printStructBody(NamedType, Out); Out << '\n'; } } @@ -3757,8 +3759,8 @@ void AssemblyWriter::printFunction(const Function *F) { Out << '"'; } maybePrintComdat(Out, *F); - if (F->getAlignment()) - Out << " align " << F->getAlignment(); + if (MaybeAlign A = F->getAlign()) + Out << " align " << A->value(); if (F->hasGC()) Out << " gc \"" << F->getGC() << '"'; if (F->hasPrefixData()) { @@ -4239,8 +4241,8 @@ void AssemblyWriter::printInstruction(const Instruction &I) { Out << ", "; writeOperand(AI->getArraySize(), true); } - if (AI->getAlignment()) { - Out << ", align " << AI->getAlignment(); + if (MaybeAlign A = AI->getAlign()) { + Out << ", align " << A->value(); } unsigned AddrSpace = AI->getType()->getAddressSpace(); @@ -4310,13 +4312,13 @@ void AssemblyWriter::printInstruction(const Instruction &I) { if (const LoadInst *LI = dyn_cast(&I)) { if (LI->isAtomic()) writeAtomic(LI->getContext(), LI->getOrdering(), LI->getSyncScopeID()); - if (LI->getAlignment()) - Out << ", align " << LI->getAlignment(); + if (MaybeAlign A = LI->getAlign()) + Out << ", align " << A->value(); } else if (const StoreInst *SI = dyn_cast(&I)) { if (SI->isAtomic()) writeAtomic(SI->getContext(), SI->getOrdering(), SI->getSyncScopeID()); - if (SI->getAlignment()) - Out << ", align " << SI->getAlignment(); + if (MaybeAlign A = SI->getAlign()) + Out << ", align " << A->value(); } else if (const AtomicCmpXchgInst *CXI = dyn_cast(&I)) { writeAtomicCmpXchg(CXI->getContext(), CXI->getSuccessOrdering(), CXI->getFailureOrdering(), CXI->getSyncScopeID()); diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h index c5bbe6571096..1153fb827b56 100644 --- a/llvm/lib/IR/AttributeImpl.h +++ b/llvm/lib/IR/AttributeImpl.h @@ -253,7 +253,8 @@ public: uint64_t getDereferenceableBytes() const; uint64_t getDereferenceableOrNullBytes() const; std::pair> getAllocSizeArgs() const; - std::pair getVScaleRangeArgs() const; + unsigned getVScaleRangeMin() const; + Optional getVScaleRangeMax() const; std::string getAsString(bool InAttrGrp) const; Type *getAttributeType(Attribute::AttrKind Kind) const; diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index f81a446d6e46..c899afae6cce 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -78,15 +78,18 @@ unpackAllocSizeArgs(uint64_t Num) { return std::make_pair(ElemSizeArg, NumElemsArg); } -static uint64_t packVScaleRangeArgs(unsigned MinValue, unsigned MaxValue) { - return uint64_t(MinValue) << 32 | MaxValue; +static uint64_t packVScaleRangeArgs(unsigned MinValue, + Optional MaxValue) { + return uint64_t(MinValue) << 32 | MaxValue.getValueOr(0); } -static std::pair unpackVScaleRangeArgs(uint64_t Value) { +static std::pair> +unpackVScaleRangeArgs(uint64_t Value) { unsigned MaxValue = Value & std::numeric_limits::max(); unsigned MinValue = Value >> 32; - return std::make_pair(MinValue, MaxValue); + return std::make_pair(MinValue, + MaxValue > 0 ? MaxValue : Optional()); } Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, @@ -354,10 +357,16 @@ std::pair> Attribute::getAllocSizeArgs() const { return unpackAllocSizeArgs(pImpl->getValueAsInt()); } -std::pair Attribute::getVScaleRangeArgs() const { +unsigned Attribute::getVScaleRangeMin() const { + assert(hasAttribute(Attribute::VScaleRange) && + "Trying to get vscale args from non-vscale attribute"); + return unpackVScaleRangeArgs(pImpl->getValueAsInt()).first; +} + +Optional Attribute::getVScaleRangeMax() const { assert(hasAttribute(Attribute::VScaleRange) && "Trying to get vscale args from non-vscale attribute"); - return unpackVScaleRangeArgs(pImpl->getValueAsInt()); + return unpackVScaleRangeArgs(pImpl->getValueAsInt()).second; } std::string Attribute::getAsString(bool InAttrGrp) const { @@ -428,13 +437,13 @@ std::string Attribute::getAsString(bool InAttrGrp) const { } if (hasAttribute(Attribute::VScaleRange)) { - unsigned MinValue, MaxValue; - std::tie(MinValue, MaxValue) = getVScaleRangeArgs(); + unsigned MinValue = getVScaleRangeMin(); + Optional MaxValue = getVScaleRangeMax(); std::string Result = "vscale_range("; Result += utostr(MinValue); Result += ','; - Result += utostr(MaxValue); + Result += utostr(MaxValue.getValueOr(0)); Result += ')'; return Result; } @@ -717,9 +726,12 @@ std::pair> AttributeSet::getAllocSizeArgs() const { : std::pair>(0, 0); } -std::pair AttributeSet::getVScaleRangeArgs() const { - return SetNode ? SetNode->getVScaleRangeArgs() - : std::pair(0, 0); +unsigned AttributeSet::getVScaleRangeMin() const { + return SetNode ? SetNode->getVScaleRangeMin() : 1; +} + +Optional AttributeSet::getVScaleRangeMax() const { + return SetNode ? SetNode->getVScaleRangeMax() : None; } std::string AttributeSet::getAsString(bool InAttrGrp) const { @@ -897,10 +909,16 @@ AttributeSetNode::getAllocSizeArgs() const { return std::make_pair(0, 0); } -std::pair AttributeSetNode::getVScaleRangeArgs() const { +unsigned AttributeSetNode::getVScaleRangeMin() const { if (auto A = findEnumAttribute(Attribute::VScaleRange)) - return A->getVScaleRangeArgs(); - return std::make_pair(0, 0); + return A->getVScaleRangeMin(); + return 1; +} + +Optional AttributeSetNode::getVScaleRangeMax() const { + if (auto A = findEnumAttribute(Attribute::VScaleRange)) + return A->getVScaleRangeMax(); + return None; } std::string AttributeSetNode::getAsString(bool InAttrGrp) const { @@ -1118,15 +1136,20 @@ AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs, } AttributeList AttributeList::get(LLVMContext &C, unsigned Index, - const AttrBuilder &B) { - if (!B.hasAttributes()) + AttributeSet Attrs) { + if (!Attrs.hasAttributes()) return {}; Index = attrIdxToArrayIdx(Index); SmallVector AttrSets(Index + 1); - AttrSets[Index] = AttributeSet::get(C, B); + AttrSets[Index] = Attrs; return getImpl(C, AttrSets); } +AttributeList AttributeList::get(LLVMContext &C, unsigned Index, + const AttrBuilder &B) { + return get(C, Index, AttributeSet::get(C, B)); +} + AttributeList AttributeList::get(LLVMContext &C, unsigned Index, ArrayRef Kinds) { SmallVector, 8> Attrs; @@ -1623,8 +1646,12 @@ std::pair> AttrBuilder::getAllocSizeArgs() const { return unpackAllocSizeArgs(getRawIntAttr(Attribute::AllocSize)); } -std::pair AttrBuilder::getVScaleRangeArgs() const { - return unpackVScaleRangeArgs(getRawIntAttr(Attribute::VScaleRange)); +unsigned AttrBuilder::getVScaleRangeMin() const { + return unpackVScaleRangeArgs(getRawIntAttr(Attribute::VScaleRange)).first; +} + +Optional AttrBuilder::getVScaleRangeMax() const { + return unpackVScaleRangeArgs(getRawIntAttr(Attribute::VScaleRange)).second; } AttrBuilder &AttrBuilder::addAlignmentAttr(MaybeAlign Align) { @@ -1669,7 +1696,7 @@ AttrBuilder &AttrBuilder::addAllocSizeAttrFromRawRepr(uint64_t RawArgs) { } AttrBuilder &AttrBuilder::addVScaleRangeAttr(unsigned MinValue, - unsigned MaxValue) { + Optional MaxValue) { return addVScaleRangeAttrFromRawRepr(packVScaleRangeArgs(MinValue, MaxValue)); } diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index d73d1e9c20b3..b8ad2b294b87 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -702,6 +702,31 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) { NewFn = Intrinsic::getDeclaration(F->getParent(), IID, Tys); return true; } + + if (Name == "arm.mve.vctp64" && + cast(F->getReturnType())->getNumElements() == 4) { + // A vctp64 returning a v4i1 is converted to return a v2i1. Rename the + // function and deal with it below in UpgradeIntrinsicCall. + rename(F); + return true; + } + // These too are changed to accept a v2i1 insteead of the old v4i1. + if (Name == "arm.mve.mull.int.predicated.v2i64.v4i32.v4i1" || + Name == "arm.mve.vqdmull.predicated.v2i64.v4i32.v4i1" || + Name == "arm.mve.vldr.gather.base.predicated.v2i64.v2i64.v4i1" || + Name == "arm.mve.vldr.gather.base.wb.predicated.v2i64.v2i64.v4i1" || + Name == "arm.mve.vldr.gather.offset.predicated.v2i64.p0i64.v2i64.v4i1" || + Name == "arm.mve.vstr.scatter.base.predicated.v2i64.v2i64.v4i1" || + Name == "arm.mve.vstr.scatter.base.wb.predicated.v2i64.v2i64.v4i1" || + Name == "arm.mve.vstr.scatter.offset.predicated.p0i64.v2i64.v2i64.v4i1" || + Name == "arm.cde.vcx1q.predicated.v2i64.v4i1" || + Name == "arm.cde.vcx1qa.predicated.v2i64.v4i1" || + Name == "arm.cde.vcx2q.predicated.v2i64.v4i1" || + Name == "arm.cde.vcx2qa.predicated.v2i64.v4i1" || + Name == "arm.cde.vcx3q.predicated.v2i64.v4i1" || + Name == "arm.cde.vcx3qa.predicated.v2i64.v4i1") + return true; + break; } @@ -1803,6 +1828,96 @@ void llvm::UpgradeInlineAsmString(std::string *AsmStr) { } } +static Value *UpgradeARMIntrinsicCall(StringRef Name, CallInst *CI, Function *F, + IRBuilder<> &Builder) { + if (Name == "mve.vctp64.old") { + // Replace the old v4i1 vctp64 with a v2i1 vctp and predicate-casts to the + // correct type. + Value *VCTP = Builder.CreateCall( + Intrinsic::getDeclaration(F->getParent(), Intrinsic::arm_mve_vctp64), + CI->getArgOperand(0), CI->getName()); + Value *C1 = Builder.CreateCall( + Intrinsic::getDeclaration( + F->getParent(), Intrinsic::arm_mve_pred_v2i, + {VectorType::get(Builder.getInt1Ty(), 2, false)}), + VCTP); + return Builder.CreateCall( + Intrinsic::getDeclaration( + F->getParent(), Intrinsic::arm_mve_pred_i2v, + {VectorType::get(Builder.getInt1Ty(), 4, false)}), + C1); + } else if (Name == "mve.mull.int.predicated.v2i64.v4i32.v4i1" || + Name == "mve.vqdmull.predicated.v2i64.v4i32.v4i1" || + Name == "mve.vldr.gather.base.predicated.v2i64.v2i64.v4i1" || + Name == "mve.vldr.gather.base.wb.predicated.v2i64.v2i64.v4i1" || + Name == "mve.vldr.gather.offset.predicated.v2i64.p0i64.v2i64.v4i1" || + Name == "mve.vstr.scatter.base.predicated.v2i64.v2i64.v4i1" || + Name == "mve.vstr.scatter.base.wb.predicated.v2i64.v2i64.v4i1" || + Name == "mve.vstr.scatter.offset.predicated.p0i64.v2i64.v2i64.v4i1" || + Name == "cde.vcx1q.predicated.v2i64.v4i1" || + Name == "cde.vcx1qa.predicated.v2i64.v4i1" || + Name == "cde.vcx2q.predicated.v2i64.v4i1" || + Name == "cde.vcx2qa.predicated.v2i64.v4i1" || + Name == "cde.vcx3q.predicated.v2i64.v4i1" || + Name == "cde.vcx3qa.predicated.v2i64.v4i1") { + std::vector Tys; + unsigned ID = CI->getIntrinsicID(); + Type *V2I1Ty = FixedVectorType::get(Builder.getInt1Ty(), 2); + switch (ID) { + case Intrinsic::arm_mve_mull_int_predicated: + case Intrinsic::arm_mve_vqdmull_predicated: + case Intrinsic::arm_mve_vldr_gather_base_predicated: + Tys = {CI->getType(), CI->getOperand(0)->getType(), V2I1Ty}; + break; + case Intrinsic::arm_mve_vldr_gather_base_wb_predicated: + case Intrinsic::arm_mve_vstr_scatter_base_predicated: + case Intrinsic::arm_mve_vstr_scatter_base_wb_predicated: + Tys = {CI->getOperand(0)->getType(), CI->getOperand(0)->getType(), + V2I1Ty}; + break; + case Intrinsic::arm_mve_vldr_gather_offset_predicated: + Tys = {CI->getType(), CI->getOperand(0)->getType(), + CI->getOperand(1)->getType(), V2I1Ty}; + break; + case Intrinsic::arm_mve_vstr_scatter_offset_predicated: + Tys = {CI->getOperand(0)->getType(), CI->getOperand(1)->getType(), + CI->getOperand(2)->getType(), V2I1Ty}; + break; + case Intrinsic::arm_cde_vcx1q_predicated: + case Intrinsic::arm_cde_vcx1qa_predicated: + case Intrinsic::arm_cde_vcx2q_predicated: + case Intrinsic::arm_cde_vcx2qa_predicated: + case Intrinsic::arm_cde_vcx3q_predicated: + case Intrinsic::arm_cde_vcx3qa_predicated: + Tys = {CI->getOperand(1)->getType(), V2I1Ty}; + break; + default: + llvm_unreachable("Unhandled Intrinsic!"); + } + + std::vector Ops; + for (Value *Op : CI->args()) { + Type *Ty = Op->getType(); + if (Ty->getScalarSizeInBits() == 1) { + Value *C1 = Builder.CreateCall( + Intrinsic::getDeclaration( + F->getParent(), Intrinsic::arm_mve_pred_v2i, + {VectorType::get(Builder.getInt1Ty(), 4, false)}), + Op); + Op = Builder.CreateCall( + Intrinsic::getDeclaration(F->getParent(), + Intrinsic::arm_mve_pred_i2v, {V2I1Ty}), + C1); + } + Ops.push_back(Op); + } + + Function *Fn = Intrinsic::getDeclaration(F->getParent(), ID, Tys); + return Builder.CreateCall(Fn, Ops, CI->getName()); + } + llvm_unreachable("Unknown function for ARM CallInst upgrade."); +} + /// Upgrade a call to an old intrinsic. All argument and return casting must be /// provided to seamlessly integrate with existing context. void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { @@ -1826,6 +1941,9 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { bool IsNVVM = Name.startswith("nvvm."); if (IsNVVM) Name = Name.substr(5); + bool IsARM = Name.startswith("arm."); + if (IsARM) + Name = Name.substr(4); if (IsX86 && Name.startswith("sse4a.movnt.")) { Module *M = F->getParent(); @@ -2289,14 +2407,12 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { if (CI->arg_size() >= 3) Rep = EmitX86Select(Builder, CI->getArgOperand(2), Rep, CI->getArgOperand(1)); - } else if (IsX86 && (Name.startswith("avx512.mask.loadu."))) { - Rep = UpgradeMaskedLoad(Builder, CI->getArgOperand(0), - CI->getArgOperand(1), CI->getArgOperand(2), - /*Aligned*/false); - } else if (IsX86 && (Name.startswith("avx512.mask.load."))) { - Rep = UpgradeMaskedLoad(Builder, CI->getArgOperand(0), - CI->getArgOperand(1),CI->getArgOperand(2), - /*Aligned*/true); + } else if (IsX86 && Name.startswith("avx512.mask.load")) { + // "avx512.mask.loadu." or "avx512.mask.load." + bool Aligned = Name[16] != 'u'; // "avx512.mask.loadu". + Rep = + UpgradeMaskedLoad(Builder, CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), Aligned); } else if (IsX86 && Name.startswith("avx512.mask.expand.load.")) { auto *ResultTy = cast(CI->getType()); Type *PtrTy = ResultTy->getElementType(); @@ -3649,6 +3765,8 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { F->getParent(), Intrinsic::convert_from_fp16, {Builder.getFloatTy()}), CI->getArgOperand(0), "h2f"); + } else if (IsARM) { + Rep = UpgradeARMIntrinsicCall(Name, CI, F, Builder); } else { llvm_unreachable("Unknown function for CallInst upgrade."); } diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp index ed1956e0f7e9..7beafc485d09 100644 --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -450,8 +450,8 @@ BasicBlock *BasicBlock::splitBasicBlockBefore(iterator I, const Twine &BBName) { void BasicBlock::replacePhiUsesWith(BasicBlock *Old, BasicBlock *New) { // N.B. This might not be a complete BasicBlock, so don't assume // that it ends with a non-phi instruction. - for (iterator II = begin(), IE = end(); II != IE; ++II) { - PHINode *PN = dyn_cast(II); + for (Instruction &I : *this) { + PHINode *PN = dyn_cast(&I); if (!PN) break; PN->replaceIncomingBlockWith(Old, New); diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp index 437fd0558447..8668fe82601c 100644 --- a/llvm/lib/IR/ConstantFold.cpp +++ b/llvm/lib/IR/ConstantFold.cpp @@ -1801,46 +1801,8 @@ Constant *llvm::ConstantFoldCompareInstruction(unsigned short pred, } else if (isa(C1) && isa(C2)) { const APFloat &C1V = cast(C1)->getValueAPF(); const APFloat &C2V = cast(C2)->getValueAPF(); - APFloat::cmpResult R = C1V.compare(C2V); - switch (pred) { - default: llvm_unreachable("Invalid FCmp Predicate"); - case FCmpInst::FCMP_FALSE: return Constant::getNullValue(ResultTy); - case FCmpInst::FCMP_TRUE: return Constant::getAllOnesValue(ResultTy); - case FCmpInst::FCMP_UNO: - return ConstantInt::get(ResultTy, R==APFloat::cmpUnordered); - case FCmpInst::FCMP_ORD: - return ConstantInt::get(ResultTy, R!=APFloat::cmpUnordered); - case FCmpInst::FCMP_UEQ: - return ConstantInt::get(ResultTy, R==APFloat::cmpUnordered || - R==APFloat::cmpEqual); - case FCmpInst::FCMP_OEQ: - return ConstantInt::get(ResultTy, R==APFloat::cmpEqual); - case FCmpInst::FCMP_UNE: - return ConstantInt::get(ResultTy, R!=APFloat::cmpEqual); - case FCmpInst::FCMP_ONE: - return ConstantInt::get(ResultTy, R==APFloat::cmpLessThan || - R==APFloat::cmpGreaterThan); - case FCmpInst::FCMP_ULT: - return ConstantInt::get(ResultTy, R==APFloat::cmpUnordered || - R==APFloat::cmpLessThan); - case FCmpInst::FCMP_OLT: - return ConstantInt::get(ResultTy, R==APFloat::cmpLessThan); - case FCmpInst::FCMP_UGT: - return ConstantInt::get(ResultTy, R==APFloat::cmpUnordered || - R==APFloat::cmpGreaterThan); - case FCmpInst::FCMP_OGT: - return ConstantInt::get(ResultTy, R==APFloat::cmpGreaterThan); - case FCmpInst::FCMP_ULE: - return ConstantInt::get(ResultTy, R!=APFloat::cmpGreaterThan); - case FCmpInst::FCMP_OLE: - return ConstantInt::get(ResultTy, R==APFloat::cmpLessThan || - R==APFloat::cmpEqual); - case FCmpInst::FCMP_UGE: - return ConstantInt::get(ResultTy, R!=APFloat::cmpLessThan); - case FCmpInst::FCMP_OGE: - return ConstantInt::get(ResultTy, R==APFloat::cmpGreaterThan || - R==APFloat::cmpEqual); - } + CmpInst::Predicate Predicate = CmpInst::Predicate(pred); + return ConstantInt::get(ResultTy, FCmpInst::compare(C1V, C2V, Predicate)); } else if (auto *C1VTy = dyn_cast(C1->getType())) { // Fast path for splatted constants. @@ -2215,9 +2177,8 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C, if (C->isNullValue()) { bool isNull = true; - for (unsigned i = 0, e = Idxs.size(); i != e; ++i) - if (!isa(Idxs[i]) && - !cast(Idxs[i])->isNullValue()) { + for (Value *Idx : Idxs) + if (!isa(Idx) && !cast(Idx)->isNullValue()) { isNull = false; break; } @@ -2233,8 +2194,8 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C, // The GEP returns a vector of pointers when one of more of // its arguments is a vector. - for (unsigned i = 0, e = Idxs.size(); i != e; ++i) { - if (auto *VT = dyn_cast(Idxs[i]->getType())) { + for (Value *Idx : Idxs) { + if (auto *VT = dyn_cast(Idx->getType())) { assert((!isa(GEPTy) || isa(GEPTy) == isa(VT)) && "Mismatched GEPTy vector types"); diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp index c66cfb6e9ac1..837be910f6d8 100644 --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -535,6 +535,9 @@ void llvm::deleteConstant(Constant *C) { case Constant::DSOLocalEquivalentVal: delete static_cast(C); break; + case Constant::NoCFIValueVal: + delete static_cast(C); + break; case Constant::UndefValueVal: delete static_cast(C); break; @@ -1296,9 +1299,10 @@ Constant *ConstantArray::getImpl(ArrayType *Ty, ArrayRef V) { if (V.empty()) return ConstantAggregateZero::get(Ty); - for (unsigned i = 0, e = V.size(); i != e; ++i) { - assert(V[i]->getType() == Ty->getElementType() && + for (Constant *C : V) { + assert(C->getType() == Ty->getElementType() && "Wrong type in array element initializer"); + (void)C; } // If this is an all-zero array, return a ConstantAggregateZero object. If @@ -1364,12 +1368,12 @@ Constant *ConstantStruct::get(StructType *ST, ArrayRef V) { isZero = V[0]->isNullValue(); // PoisonValue inherits UndefValue, so its check is not necessary. if (isUndef || isZero) { - for (unsigned i = 0, e = V.size(); i != e; ++i) { - if (!V[i]->isNullValue()) + for (Constant *C : V) { + if (!C->isNullValue()) isZero = false; - if (!isa(V[i])) + if (!isa(C)) isPoison = false; - if (isa(V[i]) || !isa(V[i])) + if (isa(C) || !isa(C)) isUndef = false; } } @@ -1962,6 +1966,47 @@ Value *DSOLocalEquivalent::handleOperandChangeImpl(Value *From, Value *To) { return nullptr; } +NoCFIValue *NoCFIValue::get(GlobalValue *GV) { + NoCFIValue *&NC = GV->getContext().pImpl->NoCFIValues[GV]; + if (!NC) + NC = new NoCFIValue(GV); + + assert(NC->getGlobalValue() == GV && + "NoCFIValue does not match the expected global value"); + return NC; +} + +NoCFIValue::NoCFIValue(GlobalValue *GV) + : Constant(GV->getType(), Value::NoCFIValueVal, &Op<0>(), 1) { + setOperand(0, GV); +} + +/// Remove the constant from the constant table. +void NoCFIValue::destroyConstantImpl() { + const GlobalValue *GV = getGlobalValue(); + GV->getContext().pImpl->NoCFIValues.erase(GV); +} + +Value *NoCFIValue::handleOperandChangeImpl(Value *From, Value *To) { + assert(From == getGlobalValue() && "Changing value does not match operand."); + + GlobalValue *GV = dyn_cast(To->stripPointerCasts()); + assert(GV && "Can only replace the operands with a global value"); + + NoCFIValue *&NewNC = getContext().pImpl->NoCFIValues[GV]; + if (NewNC) + return llvm::ConstantExpr::getBitCast(NewNC, getType()); + + getContext().pImpl->NoCFIValues.erase(getGlobalValue()); + NewNC = this; + setOperand(0, GV); + + if (GV->getType() != getType()) + mutateType(GV->getType()); + + return nullptr; +} + //---- ConstantExpr::get() implementations. // diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp index 2c396ae97499..a263d2536541 100644 --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -1696,6 +1696,14 @@ LLVMValueRef LLVMConstGEP(LLVMValueRef ConstantVal, return wrap(ConstantExpr::getGetElementPtr(Ty, Val, IdxList)); } +LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal, + LLVMValueRef *ConstantIndices, unsigned NumIndices) { + ArrayRef IdxList(unwrap(ConstantIndices, NumIndices), + NumIndices); + Constant *Val = unwrap(ConstantVal); + return wrap(ConstantExpr::getGetElementPtr(unwrap(Ty), Val, IdxList)); +} + LLVMValueRef LLVMConstInBoundsGEP(LLVMValueRef ConstantVal, LLVMValueRef *ConstantIndices, unsigned NumIndices) { @@ -1707,6 +1715,15 @@ LLVMValueRef LLVMConstInBoundsGEP(LLVMValueRef ConstantVal, return wrap(ConstantExpr::getInBoundsGetElementPtr(Ty, Val, IdxList)); } +LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal, + LLVMValueRef *ConstantIndices, + unsigned NumIndices) { + ArrayRef IdxList(unwrap(ConstantIndices, NumIndices), + NumIndices); + Constant *Val = unwrap(ConstantVal); + return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList)); +} + LLVMValueRef LLVMConstTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType) { return wrap(ConstantExpr::getTrunc(unwrap(ConstantVal), unwrap(ToType))); @@ -3007,13 +3024,17 @@ LLVMTypeRef LLVMGetAllocatedType(LLVMValueRef Alloca) { /*--.. Operations on gep instructions (only) ...............................--*/ LLVMBool LLVMIsInBounds(LLVMValueRef GEP) { - return unwrap(GEP)->isInBounds(); + return unwrap(GEP)->isInBounds(); } void LLVMSetIsInBounds(LLVMValueRef GEP, LLVMBool InBounds) { return unwrap(GEP)->setIsInBounds(InBounds); } +LLVMTypeRef LLVMGetGEPSourceElementType(LLVMValueRef GEP) { + return wrap(unwrap(GEP)->getSourceElementType()); +} + /*--.. Operations on phi nodes .............................................--*/ void LLVMAddIncoming(LLVMValueRef PhiNode, LLVMValueRef *IncomingValues, @@ -3039,7 +3060,7 @@ LLVMBasicBlockRef LLVMGetIncomingBlock(LLVMValueRef PhiNode, unsigned Index) { unsigned LLVMGetNumIndices(LLVMValueRef Inst) { auto *I = unwrap(Inst); - if (auto *GEP = dyn_cast(I)) + if (auto *GEP = dyn_cast(I)) return GEP->getNumIndices(); if (auto *EV = dyn_cast(I)) return EV->getNumIndices(); diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index 548962bd6a98..35af22034a12 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -671,11 +671,11 @@ DIBuilder::getOrCreateMacroArray(ArrayRef Elements) { DITypeRefArray DIBuilder::getOrCreateTypeArray(ArrayRef Elements) { SmallVector Elts; - for (unsigned i = 0, e = Elements.size(); i != e; ++i) { - if (Elements[i] && isa(Elements[i])) - Elts.push_back(cast(Elements[i])); + for (Metadata *E : Elements) { + if (isa_and_nonnull(E)) + Elts.push_back(cast(E)); else - Elts.push_back(Elements[i]); + Elts.push_back(E); } return DITypeRefArray(MDNode::get(VMContext, Elts)); } diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp index 2ace18048262..61b2b13bfd03 100644 --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -124,26 +124,25 @@ LayoutAlignElem::operator==(const LayoutAlignElem &rhs) const { // PointerAlignElem, PointerAlign support //===----------------------------------------------------------------------===// -PointerAlignElem PointerAlignElem::get(uint32_t AddressSpace, Align ABIAlign, - Align PrefAlign, uint32_t TypeByteWidth, - uint32_t IndexWidth) { +PointerAlignElem PointerAlignElem::getInBits(uint32_t AddressSpace, + Align ABIAlign, Align PrefAlign, + uint32_t TypeBitWidth, + uint32_t IndexBitWidth) { assert(ABIAlign <= PrefAlign && "Preferred alignment worse than ABI!"); PointerAlignElem retval; retval.AddressSpace = AddressSpace; retval.ABIAlign = ABIAlign; retval.PrefAlign = PrefAlign; - retval.TypeByteWidth = TypeByteWidth; - retval.IndexWidth = IndexWidth; + retval.TypeBitWidth = TypeBitWidth; + retval.IndexBitWidth = IndexBitWidth; return retval; } bool PointerAlignElem::operator==(const PointerAlignElem &rhs) const { - return (ABIAlign == rhs.ABIAlign - && AddressSpace == rhs.AddressSpace - && PrefAlign == rhs.PrefAlign - && TypeByteWidth == rhs.TypeByteWidth - && IndexWidth == rhs.IndexWidth); + return (ABIAlign == rhs.ABIAlign && AddressSpace == rhs.AddressSpace && + PrefAlign == rhs.PrefAlign && TypeBitWidth == rhs.TypeBitWidth && + IndexBitWidth == rhs.IndexBitWidth); } //===----------------------------------------------------------------------===// @@ -197,7 +196,7 @@ void DataLayout::reset(StringRef Desc) { E.PrefAlign, E.TypeBitWidth)) return report_fatal_error(std::move(Err)); } - if (Error Err = setPointerAlignment(0, Align(8), Align(8), 8, 8)) + if (Error Err = setPointerAlignmentInBits(0, Align(8), Align(8), 64, 64)) return report_fatal_error(std::move(Err)); if (Error Err = parseSpecifier(Desc)) @@ -318,7 +317,7 @@ Error DataLayout::parseSpecifier(StringRef Desc) { if (Error Err = ::split(Rest, ':', Split)) return Err; unsigned PointerMemSize; - if (Error Err = getIntInBytes(Tok, PointerMemSize)) + if (Error Err = getInt(Tok, PointerMemSize)) return Err; if (!PointerMemSize) return reportError("Invalid pointer size of 0 bytes"); @@ -354,13 +353,13 @@ Error DataLayout::parseSpecifier(StringRef Desc) { if (!Rest.empty()) { if (Error Err = ::split(Rest, ':', Split)) return Err; - if (Error Err = getIntInBytes(Tok, IndexSize)) + if (Error Err = getInt(Tok, IndexSize)) return Err; if (!IndexSize) return reportError("Invalid index size of 0 bytes"); } } - if (Error Err = setPointerAlignment( + if (Error Err = setPointerAlignmentInBits( AddrSpace, assumeAligned(PointerABIAlign), assumeAligned(PointerPrefAlign), PointerMemSize, IndexSize)) return Err; @@ -603,9 +602,10 @@ DataLayout::getPointerAlignElem(uint32_t AddressSpace) const { return Pointers[0]; } -Error DataLayout::setPointerAlignment(uint32_t AddrSpace, Align ABIAlign, - Align PrefAlign, uint32_t TypeByteWidth, - uint32_t IndexWidth) { +Error DataLayout::setPointerAlignmentInBits(uint32_t AddrSpace, Align ABIAlign, + Align PrefAlign, + uint32_t TypeBitWidth, + uint32_t IndexBitWidth) { if (PrefAlign < ABIAlign) return reportError( "Preferred alignment cannot be less than the ABI alignment"); @@ -615,13 +615,14 @@ Error DataLayout::setPointerAlignment(uint32_t AddrSpace, Align ABIAlign, return A.AddressSpace < AddressSpace; }); if (I == Pointers.end() || I->AddressSpace != AddrSpace) { - Pointers.insert(I, PointerAlignElem::get(AddrSpace, ABIAlign, PrefAlign, - TypeByteWidth, IndexWidth)); + Pointers.insert(I, + PointerAlignElem::getInBits(AddrSpace, ABIAlign, PrefAlign, + TypeBitWidth, IndexBitWidth)); } else { I->ABIAlign = ABIAlign; I->PrefAlign = PrefAlign; - I->TypeByteWidth = TypeByteWidth; - I->IndexWidth = IndexWidth; + I->TypeBitWidth = TypeBitWidth; + I->IndexBitWidth = IndexBitWidth; } return Error::success(); } @@ -704,13 +705,14 @@ Align DataLayout::getPointerPrefAlignment(unsigned AS) const { } unsigned DataLayout::getPointerSize(unsigned AS) const { - return getPointerAlignElem(AS).TypeByteWidth; + return divideCeil(getPointerAlignElem(AS).TypeBitWidth, 8); } unsigned DataLayout::getMaxIndexSize() const { unsigned MaxIndexSize = 0; for (auto &P : Pointers) - MaxIndexSize = std::max(MaxIndexSize, P.IndexWidth); + MaxIndexSize = + std::max(MaxIndexSize, (unsigned)divideCeil(P.TypeBitWidth, 8)); return MaxIndexSize; } @@ -723,7 +725,7 @@ unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const { } unsigned DataLayout::getIndexSize(unsigned AS) const { - return getPointerAlignElem(AS).IndexWidth; + return divideCeil(getPointerAlignElem(AS).IndexBitWidth, 8); } unsigned DataLayout::getIndexTypeSizeInBits(Type *Ty) const { @@ -901,16 +903,14 @@ int64_t DataLayout::getIndexedOffsetInType(Type *ElemTy, return Result; } -static void addElementIndex(SmallVectorImpl &Indices, TypeSize ElemSize, - APInt &Offset) { +static APInt getElementIndex(TypeSize ElemSize, APInt &Offset) { // Skip over scalable or zero size elements. Also skip element sizes larger // than the positive index space, because the arithmetic below may not be // correct in that case. unsigned BitWidth = Offset.getBitWidth(); if (ElemSize.isScalable() || ElemSize == 0 || !isUIntN(BitWidth - 1, ElemSize)) { - Indices.push_back(APInt::getZero(BitWidth)); - return; + return APInt::getZero(BitWidth); } APInt Index = Offset.sdiv(ElemSize); @@ -921,47 +921,52 @@ static void addElementIndex(SmallVectorImpl &Indices, TypeSize ElemSize, Offset += ElemSize; assert(Offset.isNonNegative() && "Remaining offset shouldn't be negative"); } - Indices.push_back(Index); + return Index; } -SmallVector DataLayout::getGEPIndicesForOffset(Type *&ElemTy, - APInt &Offset) const { - assert(ElemTy->isSized() && "Element type must be sized"); - SmallVector Indices; - addElementIndex(Indices, getTypeAllocSize(ElemTy), Offset); - while (Offset != 0) { - if (auto *ArrTy = dyn_cast(ElemTy)) { - ElemTy = ArrTy->getElementType(); - addElementIndex(Indices, getTypeAllocSize(ElemTy), Offset); - continue; - } +Optional DataLayout::getGEPIndexForOffset(Type *&ElemTy, + APInt &Offset) const { + if (auto *ArrTy = dyn_cast(ElemTy)) { + ElemTy = ArrTy->getElementType(); + return getElementIndex(getTypeAllocSize(ElemTy), Offset); + } - if (auto *VecTy = dyn_cast(ElemTy)) { - ElemTy = VecTy->getElementType(); - unsigned ElemSizeInBits = getTypeSizeInBits(ElemTy).getFixedSize(); - // GEPs over non-multiple of 8 size vector elements are invalid. - if (ElemSizeInBits % 8 != 0) - break; + if (auto *VecTy = dyn_cast(ElemTy)) { + ElemTy = VecTy->getElementType(); + unsigned ElemSizeInBits = getTypeSizeInBits(ElemTy).getFixedSize(); + // GEPs over non-multiple of 8 size vector elements are invalid. + if (ElemSizeInBits % 8 != 0) + return None; - addElementIndex(Indices, TypeSize::Fixed(ElemSizeInBits / 8), Offset); - continue; - } + return getElementIndex(TypeSize::Fixed(ElemSizeInBits / 8), Offset); + } - if (auto *STy = dyn_cast(ElemTy)) { - const StructLayout *SL = getStructLayout(STy); - uint64_t IntOffset = Offset.getZExtValue(); - if (IntOffset >= SL->getSizeInBytes()) - break; + if (auto *STy = dyn_cast(ElemTy)) { + const StructLayout *SL = getStructLayout(STy); + uint64_t IntOffset = Offset.getZExtValue(); + if (IntOffset >= SL->getSizeInBytes()) + return None; - unsigned Index = SL->getElementContainingOffset(IntOffset); - Offset -= SL->getElementOffset(Index); - ElemTy = STy->getElementType(Index); - Indices.push_back(APInt(32, Index)); - continue; - } + unsigned Index = SL->getElementContainingOffset(IntOffset); + Offset -= SL->getElementOffset(Index); + ElemTy = STy->getElementType(Index); + return APInt(32, Index); + } + + // Non-aggregate type. + return None; +} - // Can't index into non-aggregate type. - break; +SmallVector DataLayout::getGEPIndicesForOffset(Type *&ElemTy, + APInt &Offset) const { + assert(ElemTy->isSized() && "Element type must be sized"); + SmallVector Indices; + Indices.push_back(getElementIndex(getTypeAllocSize(ElemTy), Offset)); + while (Offset != 0) { + Optional Index = getGEPIndexForOffset(ElemTy, Offset); + if (!Index) + break; + Indices.push_back(*Index); } return Indices; diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index 82b20a8af91b..f1a6402fb11b 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -980,7 +980,10 @@ enum IIT_Info { IIT_STRUCT9 = 49, IIT_V256 = 50, IIT_AMX = 51, - IIT_PPCF128 = 52 + IIT_PPCF128 = 52, + IIT_V3 = 53, + IIT_EXTERNREF = 54, + IIT_FUNCREF = 55 }; static void DecodeIITType(unsigned &NextElt, ArrayRef Infos, @@ -1056,6 +1059,10 @@ static void DecodeIITType(unsigned &NextElt, ArrayRef Infos, OutputTable.push_back(IITDescriptor::getVector(2, IsScalableVector)); DecodeIITType(NextElt, Infos, Info, OutputTable); return; + case IIT_V3: + OutputTable.push_back(IITDescriptor::getVector(3, IsScalableVector)); + DecodeIITType(NextElt, Infos, Info, OutputTable); + return; case IIT_V4: OutputTable.push_back(IITDescriptor::getVector(4, IsScalableVector)); DecodeIITType(NextElt, Infos, Info, OutputTable); @@ -1092,6 +1099,14 @@ static void DecodeIITType(unsigned &NextElt, ArrayRef Infos, OutputTable.push_back(IITDescriptor::getVector(1024, IsScalableVector)); DecodeIITType(NextElt, Infos, Info, OutputTable); return; + case IIT_EXTERNREF: + OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 10)); + OutputTable.push_back(IITDescriptor::get(IITDescriptor::Struct, 0)); + return; + case IIT_FUNCREF: + OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 20)); + OutputTable.push_back(IITDescriptor::get(IITDescriptor::Integer, 8)); + return; case IIT_PTR: OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 0)); DecodeIITType(NextElt, Infos, Info, OutputTable); diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp index 9f38288095e3..b6bd25aa1234 100644 --- a/llvm/lib/IR/Globals.cpp +++ b/llvm/lib/IR/Globals.cpp @@ -126,7 +126,7 @@ void GlobalObject::setAlignment(MaybeAlign Align) { void GlobalObject::copyAttributesFrom(const GlobalObject *Src) { GlobalValue::copyAttributesFrom(Src); - setAlignment(MaybeAlign(Src->getAlignment())); + setAlignment(Src->getAlign()); setSection(Src->getSection()); } @@ -249,7 +249,7 @@ bool GlobalObject::canIncreaseAlignment() const { // alignment specified. (If it is assigned a section, the global // could be densely packed with other objects in the section, and // increasing the alignment could cause padding issues.) - if (hasSection() && getAlignment() > 0) + if (hasSection() && getAlign().hasValue()) return false; // On ELF platforms, we're further restricted in that we can't diff --git a/llvm/lib/IR/InlineAsm.cpp b/llvm/lib/IR/InlineAsm.cpp index 56932b457225..a0c48781ced5 100644 --- a/llvm/lib/IR/InlineAsm.cpp +++ b/llvm/lib/IR/InlineAsm.cpp @@ -262,12 +262,12 @@ bool InlineAsm::Verify(FunctionType *Ty, StringRef ConstStr) { unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0; unsigned NumIndirect = 0; - for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { - switch (Constraints[i].Type) { + for (const ConstraintInfo &Constraint : Constraints) { + switch (Constraint.Type) { case InlineAsm::isOutput: if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0) return false; // outputs before inputs and clobbers. - if (!Constraints[i].isIndirect) { + if (!Constraint.isIndirect) { ++NumOutputs; break; } diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index a4659da7e807..4480ec799c35 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -166,7 +166,10 @@ void Instruction::dropPoisonGeneratingFlags() { cast(this)->setIsInBounds(false); break; } - // TODO: FastMathFlags! + if (isa(this)) { + setHasNoNaNs(false); + setHasNoInfs(false); + } assert(!hasPoisonGeneratingFlags() && "must be kept in sync"); } @@ -436,17 +439,17 @@ static bool haveSameSpecialState(const Instruction *I1, const Instruction *I2, if (const AllocaInst *AI = dyn_cast(I1)) return AI->getAllocatedType() == cast(I2)->getAllocatedType() && - (AI->getAlignment() == cast(I2)->getAlignment() || + (AI->getAlign() == cast(I2)->getAlign() || IgnoreAlignment); if (const LoadInst *LI = dyn_cast(I1)) return LI->isVolatile() == cast(I2)->isVolatile() && - (LI->getAlignment() == cast(I2)->getAlignment() || + (LI->getAlign() == cast(I2)->getAlign() || IgnoreAlignment) && LI->getOrdering() == cast(I2)->getOrdering() && LI->getSyncScopeID() == cast(I2)->getSyncScopeID(); if (const StoreInst *SI = dyn_cast(I1)) return SI->isVolatile() == cast(I2)->isVolatile() && - (SI->getAlignment() == cast(I2)->getAlignment() || + (SI->getAlign() == cast(I2)->getAlign() || IgnoreAlignment) && SI->getOrdering() == cast(I2)->getOrdering() && SI->getSyncScopeID() == cast(I2)->getSyncScopeID(); diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp index ad27a6d8c08e..7798af3b19b9 100644 --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -1410,8 +1410,6 @@ bool AllocaInst::isStaticAlloca() const { void LoadInst::AssertOK() { assert(getOperand(0)->getType()->isPointerTy() && "Ptr must have pointer type."); - assert(!(isAtomic() && getAlignment() == 0) && - "Alignment required for atomic load"); } static Align computeLoadStoreDefaultAlign(Type *Ty, BasicBlock *BB) { @@ -1490,8 +1488,6 @@ void StoreInst::AssertOK() { assert(cast(getOperand(1)->getType()) ->isOpaqueOrPointeeTypeMatches(getOperand(0)->getType()) && "Ptr must be a pointer to Val type!"); - assert(!(isAtomic() && getAlignment() == 0) && - "Alignment required for atomic store"); } StoreInst::StoreInst(Value *val, Value *addr, Instruction *InsertBefore) @@ -2328,7 +2324,6 @@ bool ShuffleVectorInst::isInsertSubvectorMask(ArrayRef Mask, } Src1Elts.setBit(i); Src1Identity &= (M == (i + NumSrcElts)); - continue; } assert((Src0Elts | Src1Elts | UndefElts).isAllOnes() && "unknown shuffle elements"); @@ -4165,6 +4160,47 @@ bool ICmpInst::compare(const APInt &LHS, const APInt &RHS, }; } +bool FCmpInst::compare(const APFloat &LHS, const APFloat &RHS, + FCmpInst::Predicate Pred) { + APFloat::cmpResult R = LHS.compare(RHS); + switch (Pred) { + default: + llvm_unreachable("Invalid FCmp Predicate"); + case FCmpInst::FCMP_FALSE: + return false; + case FCmpInst::FCMP_TRUE: + return true; + case FCmpInst::FCMP_UNO: + return R == APFloat::cmpUnordered; + case FCmpInst::FCMP_ORD: + return R != APFloat::cmpUnordered; + case FCmpInst::FCMP_UEQ: + return R == APFloat::cmpUnordered || R == APFloat::cmpEqual; + case FCmpInst::FCMP_OEQ: + return R == APFloat::cmpEqual; + case FCmpInst::FCMP_UNE: + return R != APFloat::cmpEqual; + case FCmpInst::FCMP_ONE: + return R == APFloat::cmpLessThan || R == APFloat::cmpGreaterThan; + case FCmpInst::FCMP_ULT: + return R == APFloat::cmpUnordered || R == APFloat::cmpLessThan; + case FCmpInst::FCMP_OLT: + return R == APFloat::cmpLessThan; + case FCmpInst::FCMP_UGT: + return R == APFloat::cmpUnordered || R == APFloat::cmpGreaterThan; + case FCmpInst::FCMP_OGT: + return R == APFloat::cmpGreaterThan; + case FCmpInst::FCMP_ULE: + return R != APFloat::cmpGreaterThan; + case FCmpInst::FCMP_OLE: + return R == APFloat::cmpLessThan || R == APFloat::cmpEqual; + case FCmpInst::FCMP_UGE: + return R != APFloat::cmpLessThan; + case FCmpInst::FCMP_OGE: + return R == APFloat::cmpGreaterThan || R == APFloat::cmpEqual; + } +} + CmpInst::Predicate CmpInst::getFlippedSignednessPredicate(Predicate pred) { assert(CmpInst::isRelational(pred) && "Call only with non-equality predicates!"); @@ -4411,7 +4447,7 @@ void SwitchInstProfUpdateWrapper::addCase( Weights.getValue()[SI.getNumSuccessors() - 1] = *W; } else if (Weights) { Changed = true; - Weights.getValue().push_back(W ? *W : 0); + Weights.getValue().push_back(W.getValueOr(0)); } if (Weights) assert(SI.getNumSuccessors() == Weights->size() && diff --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp index 9206cd37a6d1..8f7318665cfb 100644 --- a/llvm/lib/IR/IntrinsicInst.cpp +++ b/llvm/lib/IR/IntrinsicInst.cpp @@ -468,6 +468,7 @@ bool VPIntrinsic::canIgnoreVectorLengthParam() const { } Function *VPIntrinsic::getDeclarationForParams(Module *M, Intrinsic::ID VPID, + Type *ReturnType, ArrayRef Params) { assert(isVPIntrinsic(VPID) && "not a VP intrinsic"); Function *VPFunc; @@ -486,22 +487,15 @@ Function *VPIntrinsic::getDeclarationForParams(Module *M, Intrinsic::ID VPID, break; case Intrinsic::vp_load: VPFunc = Intrinsic::getDeclaration( - M, VPID, - {Params[0]->getType()->getPointerElementType(), Params[0]->getType()}); + M, VPID, {ReturnType, Params[0]->getType()}); break; case Intrinsic::vp_gather: VPFunc = Intrinsic::getDeclaration( - M, VPID, - {VectorType::get(cast(Params[0]->getType()) - ->getElementType() - ->getPointerElementType(), - cast(Params[0]->getType())), - Params[0]->getType()}); + M, VPID, {ReturnType, Params[0]->getType()}); break; case Intrinsic::vp_store: VPFunc = Intrinsic::getDeclaration( - M, VPID, - {Params[1]->getType()->getPointerElementType(), Params[1]->getType()}); + M, VPID, {Params[0]->getType(), Params[1]->getType()}); break; case Intrinsic::vp_scatter: VPFunc = Intrinsic::getDeclaration( diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index b2909c425846..24c4a348f4da 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -386,8 +386,9 @@ template <> struct MDNodeKeyImpl { IsUnsigned(N->isUnsigned()) {} bool isKeyOf(const DIEnumerator *RHS) const { - return APInt::isSameValue(Value, RHS->getValue()) && - IsUnsigned == RHS->isUnsigned() && Name == RHS->getRawName(); + return Value.getBitWidth() == RHS->getValue().getBitWidth() && + Value == RHS->getValue() && IsUnsigned == RHS->isUnsigned() && + Name == RHS->getRawName(); } unsigned getHashValue() const { return hash_combine(Value, Name); } @@ -1424,6 +1425,8 @@ public: DenseMap DSOLocalEquivalents; + DenseMap NoCFIValues; + ConstantUniqueMap ExprConstants; ConstantUniqueMap InlineAsms; diff --git a/llvm/lib/IR/LegacyPassManager.cpp b/llvm/lib/IR/LegacyPassManager.cpp index 7bccf09012ca..bb72bec93066 100644 --- a/llvm/lib/IR/LegacyPassManager.cpp +++ b/llvm/lib/IR/LegacyPassManager.cpp @@ -886,9 +886,8 @@ void PMDataManager::recordAvailableAnalysis(Pass *P) { // implements as well. const PassInfo *PInf = TPM->findAnalysisPassInfo(PI); if (!PInf) return; - const std::vector &II = PInf->getInterfacesImplemented(); - for (unsigned i = 0, e = II.size(); i != e; ++i) - AvailableAnalysis[II[i]->getTypeInfo()] = P; + for (const PassInfo *PI : PInf->getInterfacesImplemented()) + AvailableAnalysis[PI->getTypeInfo()] = P; } // Return true if P preserves high level analysis used by other @@ -1013,10 +1012,9 @@ void PMDataManager::freePass(Pass *P, StringRef Msg, // Remove all interfaces this pass implements, for which it is also // listed as the available implementation. - const std::vector &II = PInf->getInterfacesImplemented(); - for (unsigned i = 0, e = II.size(); i != e; ++i) { - DenseMap::iterator Pos = - AvailableAnalysis.find(II[i]->getTypeInfo()); + for (const PassInfo *PI : PInf->getInterfacesImplemented()) { + DenseMap::iterator Pos = + AvailableAnalysis.find(PI->getTypeInfo()); if (Pos != AvailableAnalysis.end() && Pos->second == P) AvailableAnalysis.erase(Pos); } diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index 63ea41fba89a..a0485a59d0e0 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -750,8 +750,8 @@ void Module::setSDKVersion(const VersionTuple &V) { ConstantDataArray::get(Context, Entries)); } -VersionTuple Module::getSDKVersion() const { - auto *CM = dyn_cast_or_null(getModuleFlag("SDK Version")); +static VersionTuple getSDKVersionMD(Metadata *MD) { + auto *CM = dyn_cast_or_null(MD); if (!CM) return {}; auto *Arr = dyn_cast_or_null(CM->getValue()); @@ -775,6 +775,10 @@ VersionTuple Module::getSDKVersion() const { return Result; } +VersionTuple Module::getSDKVersion() const { + return getSDKVersionMD(getModuleFlag("SDK Version")); +} + GlobalVariable *llvm::collectUsedGlobalVariables( const Module &M, SmallVectorImpl &Vec, bool CompilerUsed) { const char *Name = CompilerUsed ? "llvm.compiler.used" : "llvm.used"; @@ -809,3 +813,13 @@ void Module::setPartialSampleProfileRatio(const ModuleSummaryIndex &Index) { } } } + +StringRef Module::getDarwinTargetVariantTriple() const { + if (const auto *MD = getModuleFlag("darwin.target_variant.triple")) + return cast(MD)->getString(); + return ""; +} + +VersionTuple Module::getDarwinTargetVariantSDKVersion() const { + return getSDKVersionMD(getModuleFlag("darwin.target_variant.SDK Version")); +} diff --git a/llvm/lib/IR/ModuleSummaryIndex.cpp b/llvm/lib/IR/ModuleSummaryIndex.cpp index 31c5cd938d03..a0ac7d3ad7d3 100644 --- a/llvm/lib/IR/ModuleSummaryIndex.cpp +++ b/llvm/lib/IR/ModuleSummaryIndex.cpp @@ -447,11 +447,17 @@ static std::string linkageToString(GlobalValue::LinkageTypes LT) { static std::string fflagsToString(FunctionSummary::FFlags F) { auto FlagValue = [](unsigned V) { return V ? '1' : '0'; }; - char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly), - FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias), - FlagValue(F.NoInline), FlagValue(F.AlwaysInline), - FlagValue(F.NoUnwind), FlagValue(F.MayThrow), - FlagValue(F.HasUnknownCall), 0}; + char FlagRep[] = {FlagValue(F.ReadNone), + FlagValue(F.ReadOnly), + FlagValue(F.NoRecurse), + FlagValue(F.ReturnDoesNotAlias), + FlagValue(F.NoInline), + FlagValue(F.AlwaysInline), + FlagValue(F.NoUnwind), + FlagValue(F.MayThrow), + FlagValue(F.HasUnknownCall), + FlagValue(F.MustBeUnreachable), + 0}; return FlagRep; } diff --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp index d15fcfbc5b9f..08c1fc931e2e 100644 --- a/llvm/lib/IR/Operator.cpp +++ b/llvm/lib/IR/Operator.cpp @@ -39,9 +39,10 @@ bool Operator::hasPoisonGeneratingFlags() const { return GEP->isInBounds() || GEP->getInRangeIndex() != None; } default: + if (const auto *FP = dyn_cast(this)) + return FP->hasNoNaNs() || FP->hasNoInfs(); return false; } - // TODO: FastMathFlags! (On instructions, but not constexpr) } Type *GEPOperator::getSourceElementType() const { @@ -89,7 +90,7 @@ bool GEPOperator::accumulateConstantOffset( assert(Offset.getBitWidth() == DL.getIndexSizeInBits(getPointerAddressSpace()) && "The offset bit width does not match DL specification."); - SmallVector Index(value_op_begin() + 1, value_op_end()); + SmallVector Index(llvm::drop_begin(operand_values())); return GEPOperator::accumulateConstantOffset(getSourceElementType(), Index, DL, Offset, ExternalAnalysis); } diff --git a/llvm/lib/IR/SSAContext.cpp b/llvm/lib/IR/SSAContext.cpp new file mode 100644 index 000000000000..a96e39f32882 --- /dev/null +++ b/llvm/lib/IR/SSAContext.cpp @@ -0,0 +1,47 @@ +//===- SSAContext.cpp -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines a specialization of the GenericSSAContext +/// template class for LLVM IR. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/SSAContext.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +BasicBlock *SSAContext::getEntryBlock(Function &F) { + return &F.getEntryBlock(); +} + +void SSAContext::setFunction(Function &Fn) { F = &Fn; } + +Printable SSAContext::print(Value *V) const { + return Printable([V](raw_ostream &Out) { V->print(Out); }); +} + +Printable SSAContext::print(Instruction *Inst) const { + return print(cast(Inst)); +} + +Printable SSAContext::print(BasicBlock *BB) const { + if (BB->hasName()) + return Printable([BB](raw_ostream &Out) { Out << BB->getName(); }); + + return Printable([BB](raw_ostream &Out) { + ModuleSlotTracker MST{BB->getParent()->getParent(), false}; + MST.incorporateFunction(*BB->getParent()); + Out << MST.getLocalSlot(BB); + }); +} diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index b475c8327874..8741ed917f9f 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -928,7 +928,7 @@ Align Value::getPointerAlignment(const DataLayout &DL) const { } llvm_unreachable("Unhandled FunctionPtrAlignType"); } - const MaybeAlign Alignment(GO->getAlignment()); + const MaybeAlign Alignment(GO->getAlign()); if (!Alignment) { if (auto *GVar = dyn_cast(GO)) { Type *ObjectType = GVar->getValueType(); diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 154b59835b01..fb7c423e54e2 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -543,7 +543,7 @@ private: void verifySwiftErrorCall(CallBase &Call, const Value *SwiftErrorVal); void verifySwiftErrorValue(const Value *SwiftErrorVal); - void verifyTailCCMustTailAttrs(AttrBuilder Attrs, StringRef Context); + void verifyTailCCMustTailAttrs(const AttrBuilder &Attrs, StringRef Context); void verifyMustTailCall(CallInst &CI); bool verifyAttributeCount(AttributeList Attrs, unsigned Params); void verifyAttributeTypes(AttributeSet Attrs, const Value *V); @@ -553,8 +553,6 @@ private: void verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, const Value *V, bool IsIntrinsic); void verifyFunctionMetadata(ArrayRef> MDs); - template - void verifyODRTypeAsScopeOperand(const MDNode &MD, T * = nullptr); void visitConstantExprsRecursively(const Constant *EntryC); void visitConstantExpr(const ConstantExpr *CE); @@ -604,26 +602,35 @@ void Verifier::visit(Instruction &I) { InstVisitor::visit(I); } -// Helper to recursively iterate over indirect users. By -// returning false, the callback can ask to stop recursing -// further. +// Helper to iterate over indirect users. By returning false, the callback can ask to stop traversing further. static void forEachUser(const Value *User, SmallPtrSet &Visited, llvm::function_ref Callback) { if (!Visited.insert(User).second) return; - for (const Value *TheNextUser : User->materialized_users()) - if (Callback(TheNextUser)) - forEachUser(TheNextUser, Visited, Callback); + + SmallVector WorkList; + append_range(WorkList, User->materialized_users()); + while (!WorkList.empty()) { + const Value *Cur = WorkList.pop_back_val(); + if (!Visited.insert(Cur).second) + continue; + if (Callback(Cur)) + append_range(WorkList, Cur->materialized_users()); + } } void Verifier::visitGlobalValue(const GlobalValue &GV) { Assert(!GV.isDeclaration() || GV.hasValidDeclarationLinkage(), "Global is external, but doesn't have external or weak linkage!", &GV); - if (const GlobalObject *GO = dyn_cast(&GV)) - Assert(GO->getAlignment() <= Value::MaximumAlignment, - "huge alignment values are unsupported", GO); + if (const GlobalObject *GO = dyn_cast(&GV)) { + + if (MaybeAlign A = GO->getAlign()) { + Assert(A->value() <= Value::MaximumAlignment, + "huge alignment values are unsupported", GO); + } + } Assert(!GV.hasAppendingLinkage() || isa(GV), "Only global variables can have appending linkage!", &GV); @@ -733,8 +740,9 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) { Value *V = Op->stripPointerCasts(); Assert(isa(V) || isa(V) || isa(V), - "invalid llvm.used member", V); - Assert(V->hasName(), "members of llvm.used must be named", V); + Twine("invalid ") + GV.getName() + " member", V); + Assert(V->hasName(), + Twine("members of ") + GV.getName() + " must be named", V); } } } @@ -860,19 +868,6 @@ void Verifier::visitNamedMDNode(const NamedMDNode &NMD) { } } -template -void Verifier::verifyODRTypeAsScopeOperand(const MDNode &MD, T *) { - if (isa(MD)) { - if (auto *N = dyn_cast_or_null(cast(MD).getScope())) - // Of all the supported tags for DICompositeType(see visitDICompositeType) - // we know that enum type cannot be a scope. - AssertDI(N->getTag() != dwarf::DW_TAG_enumeration_type, - "enum type is not a scope; check enum type ODR " - "violation", - N, &MD); - } -} - void Verifier::visitMDNode(const MDNode &MD, AreDebugLocsAllowed AllowLocs) { // Only visit each node once. Metadata can be mutually recursive, so this // avoids infinite recursion here, as well as being an optimization. @@ -882,12 +877,6 @@ void Verifier::visitMDNode(const MDNode &MD, AreDebugLocsAllowed AllowLocs) { Assert(&MD.getContext() == &Context, "MDNode context does not match Module context!", &MD); - // Makes sure when a scope operand is a ODR type, the ODR type uniquing does - // not create invalid debug metadata. - // TODO: check that the non-ODR-type scope operand is valid. - verifyODRTypeAsScopeOperand(MD); - verifyODRTypeAsScopeOperand(MD); - switch (MD.getMetadataID()) { default: llvm_unreachable("Invalid MDNode subclass"); @@ -2055,10 +2044,12 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, } if (Attrs.hasFnAttr(Attribute::VScaleRange)) { - std::pair Args = - Attrs.getFnAttrs().getVScaleRangeArgs(); + unsigned VScaleMin = Attrs.getFnAttrs().getVScaleRangeMin(); + if (VScaleMin == 0) + CheckFailed("'vscale_range' minimum must be greater than 0", V); - if (Args.first > Args.second && Args.second != 0) + Optional VScaleMax = Attrs.getFnAttrs().getVScaleRangeMax(); + if (VScaleMax && VScaleMin > VScaleMax) CheckFailed("'vscale_range' minimum cannot be greater than maximum", V); } @@ -3328,7 +3319,7 @@ void Verifier::visitCallBase(CallBase &Call) { visitInstruction(Call); } -void Verifier::verifyTailCCMustTailAttrs(AttrBuilder Attrs, +void Verifier::verifyTailCCMustTailAttrs(const AttrBuilder &Attrs, StringRef Context) { Assert(!Attrs.contains(Attribute::InAlloca), Twine("inalloca attribute not allowed in ") + Context); @@ -3733,15 +3724,15 @@ void Verifier::visitLoadInst(LoadInst &LI) { PointerType *PTy = dyn_cast(LI.getOperand(0)->getType()); Assert(PTy, "Load operand must be a pointer.", &LI); Type *ElTy = LI.getType(); - Assert(LI.getAlignment() <= Value::MaximumAlignment, - "huge alignment values are unsupported", &LI); + if (MaybeAlign A = LI.getAlign()) { + Assert(A->value() <= Value::MaximumAlignment, + "huge alignment values are unsupported", &LI); + } Assert(ElTy->isSized(), "loading unsized types is not allowed", &LI); if (LI.isAtomic()) { Assert(LI.getOrdering() != AtomicOrdering::Release && LI.getOrdering() != AtomicOrdering::AcquireRelease, "Load cannot have Release ordering", &LI); - Assert(LI.getAlignment() != 0, - "Atomic load must specify explicit alignment", &LI); Assert(ElTy->isIntOrPtrTy() || ElTy->isFloatingPointTy(), "atomic load operand must have integer, pointer, or floating point " "type!", @@ -3761,15 +3752,15 @@ void Verifier::visitStoreInst(StoreInst &SI) { Type *ElTy = SI.getOperand(0)->getType(); Assert(PTy->isOpaqueOrPointeeTypeMatches(ElTy), "Stored value type does not match pointer operand type!", &SI, ElTy); - Assert(SI.getAlignment() <= Value::MaximumAlignment, - "huge alignment values are unsupported", &SI); + if (MaybeAlign A = SI.getAlign()) { + Assert(A->value() <= Value::MaximumAlignment, + "huge alignment values are unsupported", &SI); + } Assert(ElTy->isSized(), "storing unsized types is not allowed", &SI); if (SI.isAtomic()) { Assert(SI.getOrdering() != AtomicOrdering::Acquire && SI.getOrdering() != AtomicOrdering::AcquireRelease, "Store cannot have Acquire ordering", &SI); - Assert(SI.getAlignment() != 0, - "Atomic store must specify explicit alignment", &SI); Assert(ElTy->isIntOrPtrTy() || ElTy->isFloatingPointTy(), "atomic store operand must have integer, pointer, or floating point " "type!", @@ -3820,8 +3811,10 @@ void Verifier::visitAllocaInst(AllocaInst &AI) { "Cannot allocate unsized type", &AI); Assert(AI.getArraySize()->getType()->isIntegerTy(), "Alloca array size must have integer type", &AI); - Assert(AI.getAlignment() <= Value::MaximumAlignment, - "huge alignment values are unsupported", &AI); + if (MaybeAlign A = AI.getAlign()) { + Assert(A->value() <= Value::MaximumAlignment, + "huge alignment values are unsupported", &AI); + } if (AI.isSwiftError()) { verifySwiftErrorValue(&AI); diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 6ce2ed265739..f26ef4b21996 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -1106,7 +1106,7 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { if (Conf.PreOptModuleHook && !Conf.PreOptModuleHook(0, *RegularLTO.CombinedModule)) - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); if (!Conf.CodeGenOnly) { for (const auto &R : GlobalResolutions) { @@ -1132,7 +1132,7 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { if (Conf.PostInternalizeModuleHook && !Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule)) - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); } if (!RegularLTO.EmptyCombinedModule || Conf.AlwaysEmitRegularLTOObj) { diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index be06556b0c3b..855d0fc8a8be 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -37,7 +37,6 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" -#include "llvm/Support/SmallVectorMemoryBuffer.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" @@ -413,6 +412,8 @@ static void codegen(const Config &Conf, TargetMachine *TM, if (Error Err = StreamOrErr.takeError()) report_fatal_error(std::move(Err)); std::unique_ptr &Stream = *StreamOrErr; + TM->Options.ObjectFilenameForDebug = Stream->ObjectPathName; + legacy::PassManager CodeGenPasses; CodeGenPasses.add( createImmutableModuleSummaryIndexWrapperPass(&CombinedIndex)); diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp index 088e45c9e8dc..fdc9896aca78 100644 --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -135,9 +135,8 @@ LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context) LTOCodeGenerator::~LTOCodeGenerator() {} void LTOCodeGenerator::setAsmUndefinedRefs(LTOModule *Mod) { - const std::vector &undefs = Mod->getAsmUndefinedRefs(); - for (int i = 0, e = undefs.size(); i != e; ++i) - AsmUndefinedRefs.insert(undefs[i]); + for (const StringRef &Undef : Mod->getAsmUndefinedRefs()) + AsmUndefinedRefs.insert(Undef); } bool LTOCodeGenerator::addModule(LTOModule *Mod) { diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp index 9474d8c9dafb..9aea27f0fdba 100644 --- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -378,7 +378,8 @@ std::unique_ptr codegenModule(Module &TheModule, // Run codegen now. resulting binary is in OutputBuffer. PM.run(TheModule); } - return std::make_unique(std::move(OutputBuffer)); + return std::make_unique( + std::move(OutputBuffer), /*RequiresNullTerminator=*/false); } /// Manage caching for a single Module. @@ -541,7 +542,8 @@ ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index, auto Index = buildModuleSummaryIndex(TheModule, nullptr, &PSI); WriteBitcodeToFile(TheModule, OS, true, &Index); } - return std::make_unique(std::move(OutputBuffer)); + return std::make_unique( + std::move(OutputBuffer), /*RequiresNullTerminator=*/false); } return codegenModule(TheModule, TM); diff --git a/llvm/lib/LineEditor/LineEditor.cpp b/llvm/lib/LineEditor/LineEditor.cpp index 1aa3476eb357..37c4b79f8e29 100644 --- a/llvm/lib/LineEditor/LineEditor.cpp +++ b/llvm/lib/LineEditor/LineEditor.cpp @@ -69,9 +69,8 @@ LineEditor::ListCompleterConcept::complete(StringRef Buffer, size_t Pos) const { // common prefix will then be empty. if (CommonPrefix.empty()) { Action.Kind = CompletionAction::AK_ShowCompletions; - for (std::vector::iterator I = Comps.begin(), E = Comps.end(); - I != E; ++I) - Action.Completions.push_back(I->DisplayText); + for (const Completion &Comp : Comps) + Action.Completions.push_back(Comp.DisplayText); } else { Action.Kind = CompletionAction::AK_Insert; Action.Text = CommonPrefix; diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp index bad483be197d..b475ea81d107 100644 --- a/llvm/lib/Linker/IRMover.cpp +++ b/llvm/lib/Linker/IRMover.cpp @@ -646,7 +646,7 @@ GlobalVariable *IRLinker::copyGlobalVariableProto(const GlobalVariable *SGVar) { /*init*/ nullptr, SGVar->getName(), /*insertbefore*/ nullptr, SGVar->getThreadLocalMode(), SGVar->getAddressSpace()); - NewDGV->setAlignment(MaybeAlign(SGVar->getAlignment())); + NewDGV->setAlignment(SGVar->getAlign()); NewDGV->copyAttributesFrom(SGVar); return NewDGV; } @@ -877,7 +877,7 @@ IRLinker::linkAppendingVarProto(GlobalVariable *DstGV, if (DstGV->isConstant() != SrcGV->isConstant()) return stringErr("Appending variables linked with different const'ness!"); - if (DstGV->getAlignment() != SrcGV->getAlignment()) + if (DstGV->getAlign() != SrcGV->getAlign()) return stringErr( "Appending variables with different alignment need to be linked!"); diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 2ca921017171..5c2aaddff4d1 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -168,9 +168,14 @@ public: unsigned Update, VersionTuple SDKVersion) override; void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, VersionTuple SDKVersion) override; + void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major, + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) override; void emitThumbFunc(MCSymbol *Func) override; void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; + void emitConditionalAssignment(MCSymbol *Symbol, + const MCExpr *Value) override; void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; @@ -640,6 +645,12 @@ void MCAsmStreamer::emitBuildVersion(unsigned Platform, unsigned Major, EmitEOL(); } +void MCAsmStreamer::emitDarwinTargetVariantBuildVersion( + unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { + emitBuildVersion(Platform, Major, Minor, Update, SDKVersion); +} + void MCAsmStreamer::emitThumbFunc(MCSymbol *Func) { // This needs to emit to a temporary string to get properly quoted // MCSymbols when they have spaces in them. @@ -670,6 +681,15 @@ void MCAsmStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) { MCStreamer::emitAssignment(Symbol, Value); } +void MCAsmStreamer::emitConditionalAssignment(MCSymbol *Symbol, + const MCExpr *Value) { + OS << ".lto_set_conditional "; + Symbol->print(OS, MAI); + OS << ", "; + Value->print(OS, MAI); + EmitEOL(); +} + void MCAsmStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { OS << ".weakref "; Alias->print(OS, MAI); diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index d5e9f4fc66bc..a8837bbf57c7 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -89,6 +89,7 @@ MCAssembler::MCAssembler(MCContext &Context, BundleAlignSize(0), RelaxAll(false), SubsectionsViaSymbols(false), IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) { VersionInfo.Major = 0; // Major version == 0 for "none specified" + DarwinTargetVariantVersionInfo.Major = 0; } MCAssembler::~MCAssembler() = default; @@ -109,6 +110,8 @@ void MCAssembler::reset() { LOHContainer.reset(); VersionInfo.Major = 0; VersionInfo.SDKVersion = VersionTuple(); + DarwinTargetVariantVersionInfo.Major = 0; + DarwinTargetVariantVersionInfo.SDKVersion = VersionTuple(); // reset objects owned by us if (getBackendPtr()) diff --git a/llvm/lib/MC/MCInstrAnalysis.cpp b/llvm/lib/MC/MCInstrAnalysis.cpp index 52b59185c6fc..4ed1c6286a72 100644 --- a/llvm/lib/MC/MCInstrAnalysis.cpp +++ b/llvm/lib/MC/MCInstrAnalysis.cpp @@ -39,4 +39,4 @@ Optional MCInstrAnalysis::getMemoryOperandRelocationOffset(const MCInst &Inst, uint64_t Size) const { return None; -} \ No newline at end of file +} diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp index aa94b141d8be..3edf7a3f49e6 100644 --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -92,6 +92,9 @@ public: unsigned Update, VersionTuple SDKVersion) override; void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, VersionTuple SDKVersion) override; + void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major, + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) override; void emitThumbFunc(MCSymbol *Func) override; bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; @@ -283,6 +286,13 @@ void MCMachOStreamer::emitBuildVersion(unsigned Platform, unsigned Major, Update, SDKVersion); } +void MCMachOStreamer::emitDarwinTargetVariantBuildVersion( + unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { + getAssembler().setDarwinTargetVariantBuildVersion( + (MachO::PlatformType)Platform, Major, Minor, Update, SDKVersion); +} + void MCMachOStreamer::emitThumbFunc(MCSymbol *Symbol) { // Remember that the function is a thumb function. Fixup and relocation // values will need adjusted. @@ -516,7 +526,10 @@ MCStreamer *llvm::createMachOStreamer(MCContext &Context, new MCMachOStreamer(Context, std::move(MAB), std::move(OW), std::move(CE), DWARFMustBeAtTheEnd, LabelSections); const Triple &Target = Context.getTargetTriple(); - S->emitVersionForTarget(Target, Context.getObjectFileInfo()->getSDKVersion()); + S->emitVersionForTarget( + Target, Context.getObjectFileInfo()->getSDKVersion(), + Context.getObjectFileInfo()->getDarwinTargetVariantTriple(), + Context.getObjectFileInfo()->getDarwinTargetVariantSDKVersion()); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/llvm/lib/MC/MCNullStreamer.cpp b/llvm/lib/MC/MCNullStreamer.cpp index 291d840b4f4b..40b7eba58b03 100644 --- a/llvm/lib/MC/MCNullStreamer.cpp +++ b/llvm/lib/MC/MCNullStreamer.cpp @@ -40,6 +40,9 @@ namespace { void EmitCOFFSymbolStorageClass(int StorageClass) override {} void EmitCOFFSymbolType(int Type) override {} void EndCOFFSymbolDef() override {} + void + emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, MCSymbolAttr Linkage, + MCSymbolAttr Visibility) override {} }; } diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index 9c86fcc86bcb..6604d7988c4c 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -281,6 +281,18 @@ void MCObjectStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { Symbol->setOffset(0); addPendingLabel(Symbol); } + + emitPendingAssignments(Symbol); +} + +void MCObjectStreamer::emitPendingAssignments(MCSymbol *Symbol) { + auto Assignments = pendingAssignments.find(Symbol); + if (Assignments != pendingAssignments.end()) { + for (const PendingAssignment &A : Assignments->second) + emitAssignment(A.Symbol, A.Value); + + pendingAssignments.erase(Assignments); + } } // Emit a label at a previously emitted fragment/offset position. This must be @@ -353,6 +365,19 @@ bool MCObjectStreamer::changeSectionImpl(MCSection *Section, void MCObjectStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) { getAssembler().registerSymbol(*Symbol); MCStreamer::emitAssignment(Symbol, Value); + emitPendingAssignments(Symbol); +} + +void MCObjectStreamer::emitConditionalAssignment(MCSymbol *Symbol, + const MCExpr *Value) { + const MCSymbol *Target = &cast(*Value).getSymbol(); + + // If the symbol already exists, emit the assignment. Otherwise, emit it + // later only if the symbol is also emitted. + if (Target->isRegistered()) + emitAssignment(Symbol, Value); + else + pendingAssignments[Target].push_back({Symbol, Value}); } bool MCObjectStreamer::mayHaveInstructions(MCSection &Sec) const { diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index ed9f2066dc20..705f7159d55b 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -356,8 +356,14 @@ private: /// return the contents from the current token up to the end or comma. StringRef parseStringToComma(); - bool parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip = false); + enum class AssignmentKind { + Set, + Equiv, + Equal, + LTOSetConditional, + }; + + bool parseAssignment(StringRef Name, AssignmentKind Kind); unsigned getBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind); @@ -534,6 +540,7 @@ private: DK_ADDRSIG_SYM, DK_PSEUDO_PROBE, DK_LTO_DISCARD, + DK_LTO_SET_CONDITIONAL, DK_END }; @@ -564,8 +571,8 @@ private: const fltSemantics &); // ".single", ... bool parseDirectiveFill(); // ".fill" bool parseDirectiveZero(); // ".zero" - // ".set", ".equ", ".equiv" - bool parseDirectiveSet(StringRef IDVal, bool allow_redef); + // ".set", ".equ", ".equiv", ".lto_set_conditional" + bool parseDirectiveSet(StringRef IDVal, AssignmentKind Kind); bool parseDirectiveOrg(); // ".org" // ".align{,32}", ".p2align{,w,l}" bool parseDirectiveAlign(bool IsPow2, unsigned ValueSize); @@ -1968,7 +1975,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // identifier '=' ... -> assignment statement Lex(); - return parseAssignment(IDVal, true); + return parseAssignment(IDVal, AssignmentKind::Equal); default: // Normal instruction or directive. break; @@ -2027,9 +2034,11 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, break; case DK_SET: case DK_EQU: - return parseDirectiveSet(IDVal, true); + return parseDirectiveSet(IDVal, AssignmentKind::Set); case DK_EQUIV: - return parseDirectiveSet(IDVal, false); + return parseDirectiveSet(IDVal, AssignmentKind::Equiv); + case DK_LTO_SET_CONDITIONAL: + return parseDirectiveSet(IDVal, AssignmentKind::LTOSetConditional); case DK_ASCII: return parseDirectiveAscii(IDVal, false); case DK_ASCIZ: @@ -2925,11 +2934,13 @@ void AsmParser::handleMacroExit() { ActiveMacros.pop_back(); } -bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip) { +bool AsmParser::parseAssignment(StringRef Name, AssignmentKind Kind) { MCSymbol *Sym; const MCExpr *Value; - if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym, + SMLoc ExprLoc = getTok().getLoc(); + bool AllowRedef = + Kind == AssignmentKind::Set || Kind == AssignmentKind::Equal; + if (MCParserUtils::parseAssignmentExpression(Name, AllowRedef, *this, Sym, Value)) return true; @@ -2944,9 +2955,22 @@ bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, return false; // Do the assignment. - Out.emitAssignment(Sym, Value); - if (NoDeadStrip) + switch (Kind) { + case AssignmentKind::Equal: + Out.emitAssignment(Sym, Value); + break; + case AssignmentKind::Set: + case AssignmentKind::Equiv: + Out.emitAssignment(Sym, Value); Out.emitSymbolAttribute(Sym, MCSA_NoDeadStrip); + break; + case AssignmentKind::LTOSetConditional: + if (Value->getKind() != MCExpr::SymbolRef) + return Error(ExprLoc, "expected identifier"); + + Out.emitConditionalAssignment(Sym, Value); + break; + } return false; } @@ -2998,10 +3022,11 @@ bool AsmParser::parseIdentifier(StringRef &Res) { /// ::= .equ identifier ',' expression /// ::= .equiv identifier ',' expression /// ::= .set identifier ',' expression -bool AsmParser::parseDirectiveSet(StringRef IDVal, bool allow_redef) { +/// ::= .lto_set_conditional identifier ',' expression +bool AsmParser::parseDirectiveSet(StringRef IDVal, AssignmentKind Kind) { StringRef Name; if (check(parseIdentifier(Name), "expected identifier") || parseComma() || - parseAssignment(Name, allow_redef, true)) + parseAssignment(Name, Kind)) return true; return false; } @@ -5581,6 +5606,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".addrsig_sym"] = DK_ADDRSIG_SYM; DirectiveKindMap[".pseudoprobe"] = DK_PSEUDO_PROBE; DirectiveKindMap[".lto_discard"] = DK_LTO_DISCARD; + DirectiveKindMap[".lto_set_conditional"] = DK_LTO_SET_CONDITIONAL; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { @@ -6012,12 +6038,13 @@ bool AsmParser::parseMSInlineAsm( bool isOutput = (i == 1) && Desc.mayStore(); SMLoc Start = SMLoc::getFromPointer(SymName.data()); + int64_t Size = Operand.isMemPlaceholder(Desc) ? 0 : SymName.size(); if (isOutput) { ++InputIdx; OutputDecls.push_back(OpDecl); OutputDeclsAddressOf.push_back(Operand.needAddressOf()); OutputConstraints.push_back(("=" + Constraint).str()); - AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size()); + AsmStrRewrites.emplace_back(AOK_Output, Start, Size); } else { InputDecls.push_back(OpDecl); InputDeclsAddressOf.push_back(Operand.needAddressOf()); @@ -6025,7 +6052,7 @@ bool AsmParser::parseMSInlineAsm( if (Desc.OpInfo[i - 1].isBranchTarget()) AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size()); else - AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size()); + AsmStrRewrites.emplace_back(AOK_Input, Start, Size); } } @@ -6140,13 +6167,17 @@ bool AsmParser::parseMSInlineAsm( OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label; break; case AOK_Input: - OS << '$' << InputIdx++; + if (AR.Len) + OS << '$' << InputIdx; + ++InputIdx; break; case AOK_CallInput: OS << "${" << InputIdx++ << ":P}"; break; case AOK_Output: - OS << '$' << OutputIdx++; + if (AR.Len) + OS << '$' << OutputIdx; + ++OutputIdx; break; case AOK_SizeDirective: switch (AR.Val) { diff --git a/llvm/lib/MC/MCPseudoProbe.cpp b/llvm/lib/MC/MCPseudoProbe.cpp index e35bcec8fe75..ebf38327f4dc 100644 --- a/llvm/lib/MC/MCPseudoProbe.cpp +++ b/llvm/lib/MC/MCPseudoProbe.cpp @@ -151,8 +151,8 @@ void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS, // InlineSite is unique for each pair, // so there will be no ordering of Inlinee based on MCPseudoProbeInlineTree* std::map Inlinees; - for (auto Child = Children.begin(); Child != Children.end(); ++Child) - Inlinees[Child->first] = Child->second.get(); + for (auto &Child : Children) + Inlinees[Child.first] = Child.second.get(); for (const auto &Inlinee : Inlinees) { if (Guid) { diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index f4e64b42c817..9c37a7bebe2a 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -431,6 +431,9 @@ void MCStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { TS->emitLabel(Symbol); } +void MCStreamer::emitConditionalAssignment(MCSymbol *Symbol, + const MCExpr *Value) {} + void MCStreamer::emitCFISections(bool EH, bool Debug) {} void MCStreamer::emitCFIStartProc(bool IsSimple, SMLoc Loc) { @@ -1308,45 +1311,78 @@ getMachoBuildVersionPlatformType(const Triple &Target) { llvm_unreachable("unexpected OS type"); } -void MCStreamer::emitVersionForTarget(const Triple &Target, - const VersionTuple &SDKVersion) { +void MCStreamer::emitVersionForTarget( + const Triple &Target, const VersionTuple &SDKVersion, + const Triple *DarwinTargetVariantTriple, + const VersionTuple &DarwinTargetVariantSDKVersion) { if (!Target.isOSBinFormatMachO() || !Target.isOSDarwin()) return; // Do we even know the version? if (Target.getOSMajorVersion() == 0) return; - unsigned Major = 0; - unsigned Minor = 0; - unsigned Update = 0; + VersionTuple Version; switch (Target.getOS()) { case Triple::MacOSX: case Triple::Darwin: - Target.getMacOSXVersion(Major, Minor, Update); + Target.getMacOSXVersion(Version); break; case Triple::IOS: case Triple::TvOS: - Target.getiOSVersion(Major, Minor, Update); + Version = Target.getiOSVersion(); break; case Triple::WatchOS: - Target.getWatchOSVersion(Major, Minor, Update); + Version = Target.getWatchOSVersion(); break; default: llvm_unreachable("unexpected OS type"); } - assert(Major != 0 && "A non-zero major version is expected"); - auto LinkedTargetVersion = targetVersionOrMinimumSupportedOSVersion( - Target, VersionTuple(Major, Minor, Update)); + assert(Version.getMajor() != 0 && "A non-zero major version is expected"); + auto LinkedTargetVersion = + targetVersionOrMinimumSupportedOSVersion(Target, Version); auto BuildVersionOSVersion = getMachoBuildVersionSupportedOS(Target); + bool ShouldEmitBuildVersion = false; if (BuildVersionOSVersion.empty() || - LinkedTargetVersion >= BuildVersionOSVersion) - return emitBuildVersion(getMachoBuildVersionPlatformType(Target), - LinkedTargetVersion.getMajor(), - *LinkedTargetVersion.getMinor(), - *LinkedTargetVersion.getSubminor(), SDKVersion); + LinkedTargetVersion >= BuildVersionOSVersion) { + if (Target.isMacCatalystEnvironment() && DarwinTargetVariantTriple && + DarwinTargetVariantTriple->isMacOSX()) { + emitVersionForTarget(*DarwinTargetVariantTriple, + DarwinTargetVariantSDKVersion, + /*TargetVariantTriple=*/nullptr, + /*TargetVariantSDKVersion=*/VersionTuple()); + emitDarwinTargetVariantBuildVersion( + getMachoBuildVersionPlatformType(Target), + LinkedTargetVersion.getMajor(), + LinkedTargetVersion.getMinor().getValueOr(0), + LinkedTargetVersion.getSubminor().getValueOr(0), SDKVersion); + return; + } + emitBuildVersion(getMachoBuildVersionPlatformType(Target), + LinkedTargetVersion.getMajor(), + LinkedTargetVersion.getMinor().getValueOr(0), + LinkedTargetVersion.getSubminor().getValueOr(0), + SDKVersion); + ShouldEmitBuildVersion = true; + } + + if (const Triple *TVT = DarwinTargetVariantTriple) { + if (Target.isMacOSX() && TVT->isMacCatalystEnvironment()) { + auto TVLinkedTargetVersion = + targetVersionOrMinimumSupportedOSVersion(*TVT, TVT->getiOSVersion()); + emitDarwinTargetVariantBuildVersion( + getMachoBuildVersionPlatformType(*TVT), + TVLinkedTargetVersion.getMajor(), + TVLinkedTargetVersion.getMinor().getValueOr(0), + TVLinkedTargetVersion.getSubminor().getValueOr(0), + DarwinTargetVariantSDKVersion); + } + } + + if (ShouldEmitBuildVersion) + return; emitVersionMin(getMachoVersionMinLoadCommandType(Target), LinkedTargetVersion.getMajor(), - *LinkedTargetVersion.getMinor(), - *LinkedTargetVersion.getSubminor(), SDKVersion); + LinkedTargetVersion.getMinor().getValueOr(0), + LinkedTargetVersion.getSubminor().getValueOr(0), SDKVersion); } diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp index 7773d8828931..2a93c352c68a 100644 --- a/llvm/lib/MC/MCWin64EH.cpp +++ b/llvm/lib/MC/MCWin64EH.cpp @@ -351,7 +351,7 @@ static uint32_t ARM64CountOfUnwindCodes(ArrayRef Insns) { // Unwind opcode encodings and restrictions are documented at // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, - WinEH::Instruction &inst) { + const WinEH::Instruction &inst) { uint8_t b, reg; switch (static_cast(inst.Operation)) { default: @@ -1050,10 +1050,8 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info, // Emit epilog unwind instructions for (auto &I : info->EpilogMap) { auto &EpilogInstrs = I.second; - for (uint32_t i = 0; i < EpilogInstrs.size(); i++) { - WinEH::Instruction inst = EpilogInstrs[i]; + for (const WinEH::Instruction &inst : EpilogInstrs) ARM64EmitUnwindCode(streamer, info->Begin, inst); - } } int32_t BytesMod = CodeWords * 4 - TotalCodeBytes; diff --git a/llvm/lib/MC/MachObjectWriter.cpp b/llvm/lib/MC/MachObjectWriter.cpp index 277d88cf1cd2..16941b1cb727 100644 --- a/llvm/lib/MC/MachObjectWriter.cpp +++ b/llvm/lib/MC/MachObjectWriter.cpp @@ -484,15 +484,15 @@ void MachObjectWriter::bindIndirectSymbols(MCAssembler &Asm) { // Report errors for use of .indirect_symbol not in a symbol pointer section // or stub section. - for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), - ie = Asm.indirect_symbol_end(); it != ie; ++it) { - const MCSectionMachO &Section = cast(*it->Section); + for (IndirectSymbolData &ISD : llvm::make_range(Asm.indirect_symbol_begin(), + Asm.indirect_symbol_end())) { + const MCSectionMachO &Section = cast(*ISD.Section); if (Section.getType() != MachO::S_NON_LAZY_SYMBOL_POINTERS && Section.getType() != MachO::S_LAZY_SYMBOL_POINTERS && Section.getType() != MachO::S_THREAD_LOCAL_VARIABLE_POINTERS && Section.getType() != MachO::S_SYMBOL_STUBS) { - MCSymbol &Symbol = *it->Symbol; + MCSymbol &Symbol = *ISD.Symbol; report_fatal_error("indirect symbol '" + Symbol.getName() + "' not in a symbol pointer or stub section"); } @@ -779,6 +779,17 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, LoadCommandsSize += sizeof(MachO::version_min_command); } + const MCAssembler::VersionInfoType &TargetVariantVersionInfo = + Layout.getAssembler().getDarwinTargetVariantVersionInfo(); + + // Add the target variant version info load command size, if used. + if (TargetVariantVersionInfo.Major != 0) { + ++NumLoadCommands; + assert(TargetVariantVersionInfo.EmitBuildVersion && + "target variant should use build version"); + LoadCommandsSize += sizeof(MachO::build_version_command); + } + // Add the data-in-code load command size, if used. unsigned NumDataRegions = Asm.getDataRegions().size(); if (NumDataRegions) { @@ -862,38 +873,43 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, } // Write out the deployment target information, if it's available. - if (VersionInfo.Major != 0) { - auto EncodeVersion = [](VersionTuple V) -> uint32_t { - assert(!V.empty() && "empty version"); - unsigned Update = V.getSubminor() ? *V.getSubminor() : 0; - unsigned Minor = V.getMinor() ? *V.getMinor() : 0; - assert(Update < 256 && "unencodable update target version"); - assert(Minor < 256 && "unencodable minor target version"); - assert(V.getMajor() < 65536 && "unencodable major target version"); - return Update | (Minor << 8) | (V.getMajor() << 16); - }; - uint32_t EncodedVersion = EncodeVersion( - VersionTuple(VersionInfo.Major, VersionInfo.Minor, VersionInfo.Update)); - uint32_t SDKVersion = !VersionInfo.SDKVersion.empty() - ? EncodeVersion(VersionInfo.SDKVersion) - : 0; - if (VersionInfo.EmitBuildVersion) { - // FIXME: Currently empty tools. Add clang version in the future. - W.write(MachO::LC_BUILD_VERSION); - W.write(sizeof(MachO::build_version_command)); - W.write(VersionInfo.TypeOrPlatform.Platform); - W.write(EncodedVersion); - W.write(SDKVersion); - W.write(0); // Empty tools list. - } else { - MachO::LoadCommandType LCType - = getLCFromMCVM(VersionInfo.TypeOrPlatform.Type); - W.write(LCType); - W.write(sizeof(MachO::version_min_command)); - W.write(EncodedVersion); - W.write(SDKVersion); - } - } + auto EmitDeploymentTargetVersion = + [&](const MCAssembler::VersionInfoType &VersionInfo) { + auto EncodeVersion = [](VersionTuple V) -> uint32_t { + assert(!V.empty() && "empty version"); + unsigned Update = V.getSubminor().getValueOr(0); + unsigned Minor = V.getMinor().getValueOr(0); + assert(Update < 256 && "unencodable update target version"); + assert(Minor < 256 && "unencodable minor target version"); + assert(V.getMajor() < 65536 && "unencodable major target version"); + return Update | (Minor << 8) | (V.getMajor() << 16); + }; + uint32_t EncodedVersion = EncodeVersion(VersionTuple( + VersionInfo.Major, VersionInfo.Minor, VersionInfo.Update)); + uint32_t SDKVersion = !VersionInfo.SDKVersion.empty() + ? EncodeVersion(VersionInfo.SDKVersion) + : 0; + if (VersionInfo.EmitBuildVersion) { + // FIXME: Currently empty tools. Add clang version in the future. + W.write(MachO::LC_BUILD_VERSION); + W.write(sizeof(MachO::build_version_command)); + W.write(VersionInfo.TypeOrPlatform.Platform); + W.write(EncodedVersion); + W.write(SDKVersion); + W.write(0); // Empty tools list. + } else { + MachO::LoadCommandType LCType = + getLCFromMCVM(VersionInfo.TypeOrPlatform.Type); + W.write(LCType); + W.write(sizeof(MachO::version_min_command)); + W.write(EncodedVersion); + W.write(SDKVersion); + } + }; + if (VersionInfo.Major != 0) + EmitDeploymentTargetVersion(VersionInfo); + if (TargetVariantVersionInfo.Major != 0) + EmitDeploymentTargetVersion(TargetVariantVersionInfo); // Write the data-in-code load command, if used. uint64_t DataInCodeTableEnd = RelocTableEnd + NumDataRegions * 8; diff --git a/llvm/lib/MC/TargetRegistry.cpp b/llvm/lib/MC/TargetRegistry.cpp index 0948a6b9f1a1..09684b1e5ad2 100644 --- a/llvm/lib/MC/TargetRegistry.cpp +++ b/llvm/lib/MC/TargetRegistry.cpp @@ -124,10 +124,10 @@ void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) { array_pod_sort(Targets.begin(), Targets.end(), TargetArraySortFn); OS << " Registered Targets:\n"; - for (unsigned i = 0, e = Targets.size(); i != e; ++i) { - OS << " " << Targets[i].first; - OS.indent(Width - Targets[i].first.size()) << " - " - << Targets[i].second->getShortDescription() << '\n'; + for (const auto &Target : Targets) { + OS << " " << Target.first; + OS.indent(Width - Target.first.size()) + << " - " << Target.second->getShortDescription() << '\n'; } if (Targets.empty()) OS << " (none)\n"; diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp index ce997464caa7..da8bcec7f3d4 100644 --- a/llvm/lib/Object/ArchiveWriter.cpp +++ b/llvm/lib/Object/ArchiveWriter.cpp @@ -696,7 +696,7 @@ writeArchiveToBuffer(ArrayRef NewMembers, bool WriteSymtab, return std::move(E); return std::make_unique( - std::move(ArchiveBufferVector)); + std::move(ArchiveBufferVector), /*RequiresNullTerminator=*/false); } } // namespace llvm diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index 84181ae5e501..6e56da1a31f3 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -210,6 +210,8 @@ uint32_t llvm::object::getELFRelativeRelocationType(uint32_t Machine) { return ELF::R_SPARC_RELATIVE; case ELF::EM_CSKY: return ELF::R_CKCORE_RELATIVE; + case ELF::EM_VE: + return ELF::R_VE_RELATIVE; case ELF::EM_AMDGPU: break; case ELF::EM_BPF: diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 7501661591f0..42e257516f4e 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -26,12 +26,15 @@ #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/raw_ostream.h" #include @@ -4719,3 +4722,46 @@ StringRef MachOObjectFile::mapDebugSectionName(StringRef Name) const { .Case("debug_str_offs", "debug_str_offsets") .Default(Name); } + +Expected> +MachOObjectFile::findDsymObjectMembers(StringRef Path) { + SmallString<256> BundlePath(Path); + // Normalize input path. This is necessary to accept `bundle.dSYM/`. + sys::path::remove_dots(BundlePath); + if (!sys::fs::is_directory(BundlePath) || + sys::path::extension(BundlePath) != ".dSYM") + return std::vector(); + sys::path::append(BundlePath, "Contents", "Resources", "DWARF"); + bool IsDir; + auto EC = sys::fs::is_directory(BundlePath, IsDir); + if (EC == errc::no_such_file_or_directory || (!EC && !IsDir)) + return createStringError( + EC, "%s: expected directory 'Contents/Resources/DWARF' in dSYM bundle", + Path.str().c_str()); + if (EC) + return createFileError(BundlePath, errorCodeToError(EC)); + + std::vector ObjectPaths; + for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + StringRef ObjectPath = Dir->path(); + sys::fs::file_status Status; + if (auto EC = sys::fs::status(ObjectPath, Status)) + return createFileError(ObjectPath, errorCodeToError(EC)); + switch (Status.type()) { + case sys::fs::file_type::regular_file: + case sys::fs::file_type::symlink_file: + case sys::fs::file_type::type_unknown: + ObjectPaths.push_back(ObjectPath.str()); + break; + default: /*ignore*/; + } + } + if (EC) + return createFileError(BundlePath, errorCodeToError(EC)); + if (ObjectPaths.empty()) + return createStringError(std::error_code(), + "%s: no objects found in dSYM bundle", + Path.str().c_str()); + return ObjectPaths; +} diff --git a/llvm/lib/Object/MachOUniversalWriter.cpp b/llvm/lib/Object/MachOUniversalWriter.cpp index 9673c97a10f0..ae1ff09a4f8f 100644 --- a/llvm/lib/Object/MachOUniversalWriter.cpp +++ b/llvm/lib/Object/MachOUniversalWriter.cpp @@ -19,7 +19,6 @@ #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" -#include "llvm/Support/SmallVectorMemoryBuffer.h" using namespace llvm; using namespace object; diff --git a/llvm/lib/ObjectYAML/COFFEmitter.cpp b/llvm/lib/ObjectYAML/COFFEmitter.cpp index 66ad16db1ba4..d884e2fd55cd 100644 --- a/llvm/lib/ObjectYAML/COFFEmitter.cpp +++ b/llvm/lib/ObjectYAML/COFFEmitter.cpp @@ -64,11 +64,7 @@ struct COFFParser { } bool parseSections() { - for (std::vector::iterator i = Obj.Sections.begin(), - e = Obj.Sections.end(); - i != e; ++i) { - COFFYAML::Section &Sec = *i; - + for (COFFYAML::Section &Sec : Obj.Sections) { // If the name is less than 8 bytes, store it in place, otherwise // store it in the string table. StringRef Name = Sec.Name; @@ -103,11 +99,7 @@ struct COFFParser { } bool parseSymbols() { - for (std::vector::iterator i = Obj.Symbols.begin(), - e = Obj.Symbols.end(); - i != e; ++i) { - COFFYAML::Symbol &Sym = *i; - + for (COFFYAML::Symbol &Sym : Obj.Symbols) { // If the name is less than 8 bytes, store it in place, otherwise // store it in the string table. StringRef Name = Sym.Name; diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index e0dde4433d24..9b9266998ea6 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -464,29 +464,31 @@ void ScalarBitSetTraits::bitset(IO &IO, BCaseMask(EF_MIPS_ARCH_64R6, EF_MIPS_ARCH); break; case ELF::EM_HEXAGON: - BCase(EF_HEXAGON_MACH_V2); - BCase(EF_HEXAGON_MACH_V3); - BCase(EF_HEXAGON_MACH_V4); - BCase(EF_HEXAGON_MACH_V5); - BCase(EF_HEXAGON_MACH_V55); - BCase(EF_HEXAGON_MACH_V60); - BCase(EF_HEXAGON_MACH_V62); - BCase(EF_HEXAGON_MACH_V65); - BCase(EF_HEXAGON_MACH_V66); - BCase(EF_HEXAGON_MACH_V67); - BCase(EF_HEXAGON_MACH_V67T); - BCase(EF_HEXAGON_MACH_V68); - BCase(EF_HEXAGON_ISA_V2); - BCase(EF_HEXAGON_ISA_V3); - BCase(EF_HEXAGON_ISA_V4); - BCase(EF_HEXAGON_ISA_V5); - BCase(EF_HEXAGON_ISA_V55); - BCase(EF_HEXAGON_ISA_V60); - BCase(EF_HEXAGON_ISA_V62); - BCase(EF_HEXAGON_ISA_V65); - BCase(EF_HEXAGON_ISA_V66); - BCase(EF_HEXAGON_ISA_V67); - BCase(EF_HEXAGON_ISA_V68); + BCaseMask(EF_HEXAGON_MACH_V2, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V3, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V4, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V5, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V55, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V60, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V62, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V65, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V66, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V67, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V67T, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V68, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_MACH_V69, EF_HEXAGON_MACH); + BCaseMask(EF_HEXAGON_ISA_V2, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V3, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V4, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V5, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V55, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V60, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V62, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V65, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V66, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V67, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V68, EF_HEXAGON_ISA); + BCaseMask(EF_HEXAGON_ISA_V69, EF_HEXAGON_ISA); break; case ELF::EM_AVR: BCaseMask(EF_AVR_ARCH_AVR1, EF_AVR_ARCH_MASK); diff --git a/llvm/lib/ObjectYAML/XCOFFEmitter.cpp b/llvm/lib/ObjectYAML/XCOFFEmitter.cpp index 85d1f82bfafc..cf0d058c518c 100644 --- a/llvm/lib/ObjectYAML/XCOFFEmitter.cpp +++ b/llvm/lib/ObjectYAML/XCOFFEmitter.cpp @@ -86,13 +86,13 @@ bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) { } bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) { - for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { - if (!InitSections[I].Relocations.empty()) { - InitSections[I].NumberOfRelocations = InitSections[I].Relocations.size(); - InitSections[I].FileOffsetToRelocations = CurrentOffset; + for (XCOFFYAML::Section &InitSection : InitSections) { + if (!InitSection.Relocations.empty()) { + InitSection.NumberOfRelocations = InitSection.Relocations.size(); + InitSection.FileOffsetToRelocations = CurrentOffset; uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64 : XCOFF::RelocationSerializationSize32; - CurrentOffset += InitSections[I].NumberOfRelocations * RelSize; + CurrentOffset += InitSection.NumberOfRelocations * RelSize; if (CurrentOffset > MaxRawDataSize) { ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + "exceeded when writing relocation data"); diff --git a/llvm/lib/ObjectYAML/YAML.cpp b/llvm/lib/ObjectYAML/YAML.cpp index 5dcb113d3395..54e8c627d5a1 100644 --- a/llvm/lib/ObjectYAML/YAML.cpp +++ b/llvm/lib/ObjectYAML/YAML.cpp @@ -30,9 +30,8 @@ StringRef yaml::ScalarTraits::input(StringRef Scalar, void *, return "BinaryRef hex string must contain an even number of nybbles."; // TODO: Can we improve YAMLIO to permit a more accurate diagnostic here? // (e.g. a caret pointing to the offending character). - for (unsigned I = 0, N = Scalar.size(); I != N; ++I) - if (!llvm::isHexDigit(Scalar[I])) - return "BinaryRef hex string must contain only hex digits."; + if (!llvm::all_of(Scalar, llvm::isHexDigit)) + return "BinaryRef hex string must contain only hex digits."; Val = yaml::BinaryRef(Scalar); return {}; } diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp index 19e05b9272bb..c93b7ad7f5fa 100644 --- a/llvm/lib/Option/OptTable.cpp +++ b/llvm/lib/Option/OptTable.cpp @@ -591,16 +591,16 @@ static void PrintHelpOptionList(raw_ostream &OS, StringRef Title, // Find the maximum option length. unsigned OptionFieldWidth = 0; - for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { + for (const OptionInfo &Opt : OptionHelp) { // Limit the amount of padding we are willing to give up for alignment. - unsigned Length = OptionHelp[i].Name.size(); + unsigned Length = Opt.Name.size(); if (Length <= 23) OptionFieldWidth = std::max(OptionFieldWidth, Length); } const unsigned InitialPad = 2; - for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { - const std::string &Option = OptionHelp[i].Name; + for (const OptionInfo &Opt : OptionHelp) { + const std::string &Option = Opt.Name; int Pad = OptionFieldWidth - int(Option.size()); OS.indent(InitialPad) << Option; @@ -609,7 +609,7 @@ static void PrintHelpOptionList(raw_ostream &OS, StringRef Title, OS << "\n"; Pad = OptionFieldWidth + InitialPad; } - OS.indent(Pad + 1) << OptionHelp[i].HelpText << '\n'; + OS.indent(Pad + 1) << Opt.HelpText << '\n'; } } diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 561a881bab0c..d7615ef4e9bf 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -28,6 +28,7 @@ #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CostModel.h" +#include "llvm/Analysis/CycleAnalysis.h" #include "llvm/Analysis/DDG.h" #include "llvm/Analysis/DDGPrinter.h" #include "llvm/Analysis/Delinearization.h" @@ -151,6 +152,7 @@ #include "llvm/Transforms/Scalar/DeadStoreElimination.h" #include "llvm/Transforms/Scalar/DivRemPairs.h" #include "llvm/Transforms/Scalar/EarlyCSE.h" +#include "llvm/Transforms/Scalar/FlattenCFG.h" #include "llvm/Transforms/Scalar/Float2Int.h" #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/GuardWidening.h" diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index de1b0ace7876..a6a36ff25402 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -178,6 +178,10 @@ static cl::opt EnableNoRerunSimplificationPipeline( "than once in the case that SCC mutations cause a function to be " "visited multiple times as long as the function has not been changed")); +static cl::opt EnableMergeFunctions( + "enable-merge-functions", cl::init(false), cl::Hidden, + cl::desc("Enable function merging as part of the optimization pipeline")); + PipelineTuningOptions::PipelineTuningOptions() { LoopInterleaving = true; LoopVectorization = true; @@ -187,7 +191,7 @@ PipelineTuningOptions::PipelineTuningOptions() { LicmMssaOptCap = SetLicmMssaOptCap; LicmMssaNoAccForPromotionCap = SetLicmMssaNoAccForPromotionCap; CallGraphProfile = true; - MergeFunctions = false; + MergeFunctions = EnableMergeFunctions; EagerlyInvalidateAnalyses = EnableEagerlyInvalidateAnalyses; } @@ -418,9 +422,9 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level, FPM.addPass(CorrelatedValuePropagationPass()); FPM.addPass(SimplifyCFGPass()); + FPM.addPass(InstCombinePass()); if (Level == OptimizationLevel::O3) FPM.addPass(AggressiveInstCombinePass()); - FPM.addPass(InstCombinePass()); if (!Level.isOptimizingForSize()) FPM.addPass(LibCallsShrinkWrapPass()); @@ -754,9 +758,11 @@ PassBuilder::buildInlinerPipeline(OptimizationLevel Level, return MIWP; } -ModuleInlinerPass +ModulePassManager PassBuilder::buildModuleInlinerPipeline(OptimizationLevel Level, ThinOrFullLTOPhase Phase) { + ModulePassManager MPM; + InlineParams IP = getInlineParamsFromOptLevel(Level); if (Phase == ThinOrFullLTOPhase::ThinLTOPreLink && PGOOpt && PGOOpt->Action == PGOOptions::SampleUse) @@ -773,7 +779,16 @@ PassBuilder::buildModuleInlinerPipeline(OptimizationLevel Level, // inline deferral logic in module inliner. IP.EnableDeferral = false; - return ModuleInlinerPass(IP, UseInlineAdvisor); + MPM.addPass(ModuleInlinerPass(IP, UseInlineAdvisor)); + + MPM.addPass(createModuleToFunctionPassAdaptor( + buildFunctionSimplificationPipeline(Level, Phase), + PTO.EagerlyInvalidateAnalyses)); + + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor( + CoroSplitPass(Level != OptimizationLevel::O0))); + + return MPM; } ModulePassManager @@ -980,26 +995,28 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, FPM.addPass(InstCombinePass()); if (Level.getSpeedupLevel() > 1 && ExtraVectorizerPasses) { + ExtraVectorPassManager ExtraPasses; // At higher optimization levels, try to clean up any runtime overlap and // alignment checks inserted by the vectorizer. We want to track correlated // runtime checks for two inner loops in the same outer loop, fold any // common computations, hoist loop-invariant aspects out of any outer loop, // and unswitch the runtime checks if possible. Once hoisted, we may have // dead (or speculatable) control flows or more combining opportunities. - FPM.addPass(EarlyCSEPass()); - FPM.addPass(CorrelatedValuePropagationPass()); - FPM.addPass(InstCombinePass()); + ExtraPasses.addPass(EarlyCSEPass()); + ExtraPasses.addPass(CorrelatedValuePropagationPass()); + ExtraPasses.addPass(InstCombinePass()); LoopPassManager LPM; LPM.addPass(LICMPass(PTO.LicmMssaOptCap, PTO.LicmMssaNoAccForPromotionCap)); LPM.addPass(SimpleLoopUnswitchPass(/* NonTrivial */ Level == OptimizationLevel::O3)); - FPM.addPass( + ExtraPasses.addPass( RequireAnalysisPass()); - FPM.addPass( + ExtraPasses.addPass( createFunctionToLoopPassAdaptor(std::move(LPM), /*UseMemorySSA=*/true, /*UseBlockFrequencyInfo=*/true)); - FPM.addPass(SimplifyCFGPass()); - FPM.addPass(InstCombinePass()); + ExtraPasses.addPass(SimplifyCFGPass()); + ExtraPasses.addPass(InstCombinePass()); + FPM.addPass(std::move(ExtraPasses)); } // Now that we've formed fast to execute loop structures, we do further @@ -1149,8 +1166,9 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, // Disable header duplication at -Oz. LPM.addPass(LoopRotatePass(Level != OptimizationLevel::Oz, LTOPreLink)); // Some loops may have become dead by now. Try to delete them. - // FIXME: see disscussion in https://reviews.llvm.org/D112851 - // this may need to be revisited once GVN is more powerful. + // FIXME: see discussion in https://reviews.llvm.org/D112851, + // this may need to be revisited once we run GVN before loop deletion + // in the simplification pipeline. LPM.addPass(LoopDeletionPass()); OptimizePM.addPass(createFunctionToLoopPassAdaptor( std::move(LPM), /*UseMemorySSA=*/false, /*UseBlockFrequencyInfo=*/false)); @@ -1167,23 +1185,6 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, addVectorPasses(Level, OptimizePM, /* IsFullLTO */ false); - // Split out cold code. Splitting is done late to avoid hiding context from - // other optimizations and inadvertently regressing performance. The tradeoff - // is that this has a higher code size cost than splitting early. - if (EnableHotColdSplit && !LTOPreLink) - MPM.addPass(HotColdSplittingPass()); - - // Search the code for similar regions of code. If enough similar regions can - // be found where extracting the regions into their own function will decrease - // the size of the program, we extract the regions, a deduplicate the - // structurally similar regions. - if (EnableIROutliner) - MPM.addPass(IROutlinerPass()); - - // Merge functions if requested. - if (PTO.MergeFunctions) - MPM.addPass(MergeFunctionsPass()); - // LoopSink pass sinks instructions hoisted by LICM, which serves as a // canonicalization pass that enables other optimizations. As a result, // LoopSink pass needs to be a very late IR pass to avoid undoing LICM @@ -1211,6 +1212,23 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, for (auto &C : OptimizerLastEPCallbacks) C(MPM, Level); + // Split out cold code. Splitting is done late to avoid hiding context from + // other optimizations and inadvertently regressing performance. The tradeoff + // is that this has a higher code size cost than splitting early. + if (EnableHotColdSplit && !LTOPreLink) + MPM.addPass(HotColdSplittingPass()); + + // Search the code for similar regions of code. If enough similar regions can + // be found where extracting the regions into their own function will decrease + // the size of the program, we extract the regions, a deduplicate the + // structurally similar regions. + if (EnableIROutliner) + MPM.addPass(IROutlinerPass()); + + // Merge functions if requested. + if (PTO.MergeFunctions) + MPM.addPass(MergeFunctionsPass()); + if (PTO.CallGraphProfile) MPM.addPass(CGProfilePass()); @@ -1521,9 +1539,9 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level, // function pointers. When this happens, we often have to resolve varargs // calls, etc, so let instcombine do this. FunctionPassManager PeepholeFPM; + PeepholeFPM.addPass(InstCombinePass()); if (Level == OptimizationLevel::O3) PeepholeFPM.addPass(AggressiveInstCombinePass()); - PeepholeFPM.addPass(InstCombinePass()); invokePeepholeEPCallbacks(PeepholeFPM, Level); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(PeepholeFPM), diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index c2032b5b8276..74613a7fcce0 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -185,6 +185,7 @@ FUNCTION_ANALYSIS("aa", AAManager()) FUNCTION_ANALYSIS("assumptions", AssumptionAnalysis()) FUNCTION_ANALYSIS("block-freq", BlockFrequencyAnalysis()) FUNCTION_ANALYSIS("branch-prob", BranchProbabilityAnalysis()) +FUNCTION_ANALYSIS("cycles", CycleAnalysis()) FUNCTION_ANALYSIS("domtree", DominatorTreeAnalysis()) FUNCTION_ANALYSIS("postdomtree", PostDominatorTreeAnalysis()) FUNCTION_ANALYSIS("demanded-bits", DemandedBitsAnalysis()) @@ -202,6 +203,7 @@ FUNCTION_ANALYSIS("no-op-function", NoOpFunctionAnalysis()) FUNCTION_ANALYSIS("opt-remark-emit", OptimizationRemarkEmitterAnalysis()) FUNCTION_ANALYSIS("scalar-evolution", ScalarEvolutionAnalysis()) FUNCTION_ANALYSIS("should-not-run-function-passes", ShouldNotRunFunctionPassesAnalysis()) +FUNCTION_ANALYSIS("should-run-extra-vector-passes", ShouldRunExtraVectorPasses()) FUNCTION_ANALYSIS("stack-safety-local", StackSafetyAnalysis()) FUNCTION_ANALYSIS("targetlibinfo", TargetLibraryAnalysis()) FUNCTION_ANALYSIS("targetir", @@ -253,6 +255,7 @@ FUNCTION_PASS("dse", DSEPass()) FUNCTION_PASS("dot-cfg", CFGPrinterPass()) FUNCTION_PASS("dot-cfg-only", CFGOnlyPrinterPass()) FUNCTION_PASS("fix-irreducible", FixIrreduciblePass()) +FUNCTION_PASS("flattencfg", FlattenCFGPass()) FUNCTION_PASS("make-guards-explicit", MakeGuardsExplicitPass()) FUNCTION_PASS("gvn-hoist", GVNHoistPass()) FUNCTION_PASS("gvn-sink", GVNSinkPass()) @@ -303,6 +306,7 @@ FUNCTION_PASS("print", AssumptionPrinterPass(dbgs())) FUNCTION_PASS("print", BlockFrequencyPrinterPass(dbgs())) FUNCTION_PASS("print", BranchProbabilityPrinterPass(dbgs())) FUNCTION_PASS("print", CostModelPrinterPass(dbgs())) +FUNCTION_PASS("print", CycleInfoPrinterPass(dbgs())) FUNCTION_PASS("print", DependenceAnalysisPrinterPass(dbgs())) FUNCTION_PASS("print", DivergenceAnalysisPrinterPass(dbgs())) FUNCTION_PASS("print", DominatorTreePrinterPass(dbgs())) diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp index 27a6c519ff82..23c825c78713 100644 --- a/llvm/lib/Passes/StandardInstrumentations.cpp +++ b/llvm/lib/Passes/StandardInstrumentations.cpp @@ -1262,11 +1262,6 @@ void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) { namespace { -enum IRChangeDiffType { InBefore, InAfter, IsCommon, NumIRChangeDiffTypes }; - -// Describe where a given element exists. -std::string Colours[NumIRChangeDiffTypes]; - class DisplayNode; class DotCfgDiffDisplayGraph; @@ -1274,19 +1269,19 @@ class DotCfgDiffDisplayGraph; class DisplayElement { public: // Is this in before, after, or both? - IRChangeDiffType getType() const { return Type; } + StringRef getColour() const { return Colour; } protected: - DisplayElement(IRChangeDiffType T) : Type(T) {} - const IRChangeDiffType Type; + DisplayElement(StringRef Colour) : Colour(Colour) {} + const StringRef Colour; }; // An edge representing a transition between basic blocks in the // dot-cfg-changes graph. class DisplayEdge : public DisplayElement { public: - DisplayEdge(std::string V, DisplayNode &Node, IRChangeDiffType T) - : DisplayElement(T), Value(V), Node(Node) {} + DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour) + : DisplayElement(Colour), Value(Value), Node(Node) {} // The value on which the transition is made. std::string getValue() const { return Value; } // The node (representing a basic block) reached by this transition. @@ -1302,8 +1297,8 @@ class DisplayNode : public DisplayElement { public: // \p C is the content for the node, \p T indicates the colour for the // outline of the node - DisplayNode(std::string C, IRChangeDiffType T) - : DisplayElement(T), Content(C) {} + DisplayNode(std::string Content, StringRef Colour) + : DisplayElement(Colour), Content(Content) {} // Iterator to the child nodes. Required by GraphWriter. using ChildIterator = std::unordered_set::const_iterator; @@ -1315,13 +1310,13 @@ public: EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); } EdgeIterator edges_end() const { return EdgePtrs.cend(); } - // Create an edge to \p Node on value \p V, with type \p T. - void createEdge(StringRef V, DisplayNode &Node, IRChangeDiffType T); + // Create an edge to \p Node on value \p Value, with colour \p Colour. + void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour); // Return the content of this node. std::string getContent() const { return Content; } - // Return the type of the edge to node \p S. + // Return the edge to node \p S. const DisplayEdge &getEdge(const DisplayNode &To) const { assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge."); return *EdgeMap.find(&To)->second; @@ -1383,9 +1378,9 @@ public: } // Create a node. - void createNode(std::string C, IRChangeDiffType T) { + void createNode(std::string C, StringRef Colour) { assert(!NodeGenerationComplete && "Unexpected node creation"); - Nodes.emplace_back(C, T); + Nodes.emplace_back(C, Colour); } // Return the node at index \p N to avoid problems with vectors reallocating. DisplayNode &getNode(unsigned N) { @@ -1408,13 +1403,13 @@ public: // Return a string with colour information for Dot. Required by GraphWriter. std::string getNodeAttributes(const DisplayNode &Node) const { - return attribute(Node.getType()); + return attribute(Node.getColour()); } // Return a string with colour information for Dot. Required by GraphWriter. std::string getEdgeColorAttr(const DisplayNode &From, const DisplayNode &To) const { - return attribute(From.getEdge(To).getType()); + return attribute(From.getEdge(To).getColour()); } // Get the starting basic block. Required by GraphWriter. @@ -1425,7 +1420,9 @@ public: protected: // Return the string containing the colour to use as a Dot attribute. - std::string attribute(IRChangeDiffType T) const; + std::string attribute(StringRef Colour) const { + return "color=" + Colour.str(); + } bool NodeGenerationComplete = false; const std::string GraphName; @@ -1434,10 +1431,10 @@ protected: DisplayNode *EntryNode = nullptr; }; -void DisplayNode::createEdge(StringRef V, DisplayNode &Node, - IRChangeDiffType T) { +void DisplayNode::createEdge(StringRef Value, DisplayNode &Node, + StringRef Colour) { assert(!AllEdgesCreated && "Expected to be able to still create edges."); - Edges.emplace_back(V.str(), Node, T); + Edges.emplace_back(Value.str(), Node, Colour); Children.insert(&Node); } @@ -1458,13 +1455,14 @@ public: DotCfgDiffNode() = delete; // Create a node in Dot difference graph \p G representing the basic block - // represented by \p BD with type \p T (where it exists). + // represented by \p BD with colour \p Colour (where it exists). DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT &BD, - IRChangeDiffType T) - : Graph(G), N(N), Data{&BD, nullptr}, Type(T) {} + StringRef Colour) + : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {} DotCfgDiffNode(const DotCfgDiffNode &DN) - : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]}, Type(DN.Type), - EdgesMap(DN.EdgesMap), Children(DN.Children), Edges(DN.Edges) {} + : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]}, + Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children), + Edges(DN.Edges) {} unsigned getIndex() const { return N; } @@ -1473,29 +1471,29 @@ public: assert(Data[0] && "Expected Data[0] to be set."); return Data[0]->getLabel(); } - // Return where this block exists. - IRChangeDiffType getType() const { return Type; } + // Return the colour for this block + StringRef getColour() const { return Colour; } // Change this basic block from being only in before to being common. // Save the pointer to \p Other. void setCommon(const BlockDataT &Other) { assert(!Data[1] && "Expected only one block datum"); Data[1] = &Other; - Type = IsCommon; + Colour = CommonColour; } - // Add an edge to \p E of type {\p Value, \p T}. - void addEdge(unsigned E, StringRef Value, IRChangeDiffType T) { + // Add an edge to \p E of colour {\p Value, \p Colour}. + void addEdge(unsigned E, StringRef Value, StringRef Colour) { // This is a new edge or it is an edge being made common. - assert((EdgesMap.count(E) == 0 || T == IsCommon) && - "Unexpected edge count and type."); - EdgesMap[E] = {Value.str(), T}; + assert((EdgesMap.count(E) == 0 || Colour == CommonColour) && + "Unexpected edge count and color."); + EdgesMap[E] = {Value.str(), Colour}; } // Record the children and create edges. void finalize(DotCfgDiff &G); - // Return the type of the edge to node \p S. - std::pair getEdge(const unsigned S) const { + // Return the colour of the edge to node \p S. + StringRef getEdgeColour(const unsigned S) const { assert(EdgesMap.count(S) == 1 && "Expected to find edge."); - return EdgesMap.at(S); + return EdgesMap.at(S).second; } // Return the string representing the basic block. @@ -1508,8 +1506,8 @@ protected: DotCfgDiff &Graph; const unsigned N; const BlockDataT *Data[2]; - IRChangeDiffType Type; - std::map> EdgesMap; + StringRef Colour; + std::map> EdgesMap; std::vector Children; std::vector Edges; }; @@ -1552,12 +1550,11 @@ public: protected: // Return the string surrounded by HTML to make it the appropriate colour. - std::string colourize(std::string S, IRChangeDiffType T) const; + std::string colourize(std::string S, StringRef Colour) const; - void createNode(StringRef Label, const BlockDataT &BD, - IRChangeDiffType T) { + void createNode(StringRef Label, const BlockDataT &BD, StringRef C) { unsigned Pos = Nodes.size(); - Nodes.emplace_back(*this, Pos, BD, T); + Nodes.emplace_back(*this, Pos, BD, C); NodePosition.insert({Label, Pos}); } @@ -1572,7 +1569,7 @@ protected: }; std::string DotCfgDiffNode::getBodyContent() const { - if (Type == IsCommon) { + if (Colour == CommonColour) { assert(Data[1] && "Expected Data[1] to be set."); StringRef SR[2]; @@ -1586,11 +1583,11 @@ std::string DotCfgDiffNode::getBodyContent() const { } SmallString<80> OldLineFormat = formatv( - "%l
", Colours[InBefore]); + "%l
", BeforeColour); SmallString<80> NewLineFormat = formatv( - "%l
", Colours[InAfter]); + "%l
", AfterColour); SmallString<80> UnchangedLineFormat = formatv( - "%l
", Colours[IsCommon]); + "%l
", CommonColour); std::string Diff = Data[0]->getLabel().str(); Diff += ":\n
" + doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]), @@ -1625,7 +1622,7 @@ std::string DotCfgDiffNode::getBodyContent() const { // drop predecessors as they can be big and are redundant BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front(); - std::string S = "" + Label.str() + ":"; + std::string S = "" + Label.str() + ":"; // align each line to the left. while (BS1.size()) { @@ -1638,26 +1635,22 @@ std::string DotCfgDiffNode::getBodyContent() const { return S; } -std::string DotCfgDiff::colourize(std::string S, IRChangeDiffType T) const { +std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const { if (S.length() == 0) return S; - return "" + S + ""; -} - -std::string DotCfgDiffDisplayGraph::attribute(IRChangeDiffType T) const { - return "color=" + Colours[T]; + return "" + S + ""; } DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT &Before, const FuncDataT &After) : GraphName(Title.str()) { - StringMap EdgesMap; + StringMap EdgesMap; // Handle each basic block in the before IR. for (auto &B : Before.getData()) { StringRef Label = B.getKey(); const BlockDataT &BD = B.getValue(); - createNode(Label, BD, InBefore); + createNode(Label, BD, BeforeColour); // Create transitions with names made up of the from block label, the value // on which the transition is made and the to block label. @@ -1666,7 +1659,7 @@ DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT &Before, Sink != E; ++Sink) { std::string Key = (Label + " " + Sink->getKey().str()).str() + " " + BD.getData().getSuccessorLabel(Sink->getKey()).str(); - EdgesMap.insert({Key, InBefore}); + EdgesMap.insert({Key, BeforeColour}); } } @@ -1677,7 +1670,7 @@ DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT &Before, unsigned C = NodePosition.count(Label); if (C == 0) // This only exists in the after IR. Create the node. - createNode(Label, BD, InAfter); + createNode(Label, BD, AfterColour); else { assert(C == 1 && "Unexpected multiple nodes."); Nodes[NodePosition[Label]].setCommon(BD); @@ -1690,9 +1683,9 @@ DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT &Before, BD.getData().getSuccessorLabel(Sink->getKey()).str(); unsigned C = EdgesMap.count(Key); if (C == 0) - EdgesMap.insert({Key, InAfter}); + EdgesMap.insert({Key, AfterColour}); else { - EdgesMap[Key] = IsCommon; + EdgesMap[Key] = CommonColour; } } } @@ -1712,18 +1705,18 @@ DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT &Before, DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]]; assert(NodePosition.count(Sink) == 1 && "Expected to find node."); unsigned SinkNode = NodePosition[Sink]; - IRChangeDiffType T = E.second; + StringRef Colour = E.second; // Look for an edge from Source to Sink if (EdgeLabels.count(SourceSink) == 0) - EdgeLabels.insert({SourceSink, colourize(Value.str(), T)}); + EdgeLabels.insert({SourceSink, colourize(Value.str(), Colour)}); else { StringRef V = EdgeLabels.find(SourceSink)->getValue(); - std::string NV = colourize(V.str() + " " + Value.str(), T); - T = IsCommon; + std::string NV = colourize(V.str() + " " + Value.str(), Colour); + Colour = CommonColour; EdgeLabels[SourceSink] = NV; } - SourceNode.addEdge(SinkNode, Value, T); + SourceNode.addEdge(SinkNode, Value, Colour); } for (auto &I : Nodes) I.finalize(*this); @@ -1744,7 +1737,7 @@ DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title, for (auto &I : Nodes) { if (I.getIndex() == Entry) EntryIndex = Index; - G.createNode(I.getBodyContent(), I.getType()); + G.createNode(I.getBodyContent(), I.getColour()); NodeMap.insert({I.getIndex(), Index++}); } assert(EntryIndex >= 0 && "Expected entry node index to be set."); @@ -1766,12 +1759,12 @@ void DotCfgDiffNode::createDisplayEdges( for (auto I : Edges) { unsigned SinkNodeIndex = I; - IRChangeDiffType Type = getEdge(SinkNodeIndex).second; + StringRef Colour = getEdgeColour(SinkNodeIndex); const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex); StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex); DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex()); - SourceDisplayNode.createEdge(Label, SinkDisplayNode, Type); + SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour); } SourceDisplayNode.createEdgeMap(); } @@ -1891,12 +1884,7 @@ DCData::DCData(const BasicBlock &B) { } DotCfgChangeReporter::DotCfgChangeReporter(bool Verbose) - : ChangeReporter>(Verbose) { - // Set up the colours based on the hidden options. - Colours[InBefore] = BeforeColour; - Colours[InAfter] = AfterColour; - Colours[IsCommon] = CommonColour; -} + : ChangeReporter>(Verbose) {} void DotCfgChangeReporter::handleFunctionCompare( StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider, diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp index ab3487ecffe8..34e0c5ebcd58 100644 --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -110,6 +110,18 @@ static std::string getInstrProfErrString(instrprof_error Err, case instrprof_error::malformed: OS << "malformed instrumentation profile data"; break; + case instrprof_error::missing_debug_info_for_correlation: + OS << "debug info for correlation is required"; + break; + case instrprof_error::unexpected_debug_info_for_correlation: + OS << "debug info for correlation is not necessary"; + break; + case instrprof_error::unable_to_correlate_profile: + OS << "unable to correlate profile"; + break; + case instrprof_error::unsupported_debug_format: + OS << "unsupported debug info format (only DWARF is supported)"; + break; case instrprof_error::invalid_prof: OS << "invalid profile created. Please file a bug " "at: " BUG_REPORT_URL @@ -533,8 +545,8 @@ Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { void InstrProfRecord::accumulateCounts(CountSumOrPercent &Sum) const { uint64_t FuncSum = 0; Sum.NumEntries += Counts.size(); - for (size_t F = 0, E = Counts.size(); F < E; ++F) - FuncSum += Counts[F]; + for (uint64_t Count : Counts) + FuncSum += Count; Sum.CountSum += FuncSum; for (uint32_t VK = IPVK_First; VK <= IPVK_Last; ++VK) { @@ -674,9 +686,9 @@ void InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input, void InstrProfValueSiteRecord::scale(uint64_t N, uint64_t D, function_ref Warn) { - for (auto I = ValueData.begin(), IE = ValueData.end(); I != IE; ++I) { + for (InstrProfValueData &I : ValueData) { bool Overflowed; - I->Count = SaturatingMultiply(I->Count, N, &Overflowed) / D; + I.Count = SaturatingMultiply(I.Count, N, &Overflowed) / D; if (Overflowed) Warn(instrprof_error::counter_overflow); } @@ -1175,7 +1187,8 @@ bool canRenameComdatFunc(const Function &F, bool CheckAddressTaken) { // Create a COMDAT variable INSTR_PROF_RAW_VERSION_VAR to make the runtime // aware this is an ir_level profile so it can set the version flag. GlobalVariable *createIRLevelProfileFlagVar(Module &M, bool IsCS, - bool InstrEntryBBEnabled) { + bool InstrEntryBBEnabled, + bool DebugInfoCorrelate) { const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); Type *IntTy64 = Type::getInt64Ty(M.getContext()); uint64_t ProfileVersion = (INSTR_PROF_RAW_VERSION | VARIANT_MASK_IR_PROF); @@ -1183,6 +1196,8 @@ GlobalVariable *createIRLevelProfileFlagVar(Module &M, bool IsCS, ProfileVersion |= VARIANT_MASK_CSIR_PROF; if (InstrEntryBBEnabled) ProfileVersion |= VARIANT_MASK_INSTR_ENTRY; + if (DebugInfoCorrelate) + ProfileVersion |= VARIANT_MASK_DBG_CORRELATE; auto IRLevelVersionVariable = new GlobalVariable( M, IntTy64, true, GlobalValue::WeakAnyLinkage, Constant::getIntegerValue(IntTy64, APInt(64, ProfileVersion)), VarName); diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp new file mode 100644 index 000000000000..f9c113027da2 --- /dev/null +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -0,0 +1,264 @@ +//===-- InstrProfCorrelator.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ProfileData/InstrProfCorrelator.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +#define DEBUG_TYPE "correlator" + +using namespace llvm; + +/// Get the __llvm_prf_cnts section. +Expected getCountersSection(const object::ObjectFile &Obj) { + for (auto &Section : Obj.sections()) + if (auto SectionName = Section.getName()) + if (SectionName.get() == INSTR_PROF_CNTS_SECT_NAME) + return Section; + return make_error( + instrprof_error::unable_to_correlate_profile); +} + +const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name"; +const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash"; +const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters"; + +llvm::Expected> +InstrProfCorrelator::Context::get(std::unique_ptr Buffer, + const object::ObjectFile &Obj) { + auto CountersSection = getCountersSection(Obj); + if (auto Err = CountersSection.takeError()) + return std::move(Err); + auto C = std::make_unique(); + C->Buffer = std::move(Buffer); + C->CountersSectionStart = CountersSection->getAddress(); + C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize(); + C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost; + return Expected>(std::move(C)); +} + +llvm::Expected> +InstrProfCorrelator::get(StringRef DebugInfoFilename) { + auto DsymObjectsOrErr = + object::MachOObjectFile::findDsymObjectMembers(DebugInfoFilename); + if (auto Err = DsymObjectsOrErr.takeError()) + return std::move(Err); + if (!DsymObjectsOrErr->empty()) { + // TODO: Enable profile correlation when there are multiple objects in a + // dSYM bundle. + if (DsymObjectsOrErr->size() > 1) + return createStringError( + std::error_code(), + "Profile correlation using multiple objects is not yet supported"); + DebugInfoFilename = *DsymObjectsOrErr->begin(); + } + auto BufferOrErr = + errorOrToExpected(MemoryBuffer::getFile(DebugInfoFilename)); + if (auto Err = BufferOrErr.takeError()) + return std::move(Err); + + return get(std::move(*BufferOrErr)); +} + +llvm::Expected> +InstrProfCorrelator::get(std::unique_ptr Buffer) { + auto BinOrErr = object::createBinary(*Buffer); + if (auto Err = BinOrErr.takeError()) + return std::move(Err); + + if (auto *Obj = dyn_cast(BinOrErr->get())) { + auto CtxOrErr = Context::get(std::move(Buffer), *Obj); + if (auto Err = CtxOrErr.takeError()) + return std::move(Err); + auto T = Obj->makeTriple(); + if (T.isArch64Bit()) + return InstrProfCorrelatorImpl::get(std::move(*CtxOrErr), *Obj); + if (T.isArch32Bit()) + return InstrProfCorrelatorImpl::get(std::move(*CtxOrErr), *Obj); + } + return make_error( + instrprof_error::unable_to_correlate_profile); +} + +namespace llvm { + +template <> +InstrProfCorrelatorImpl::InstrProfCorrelatorImpl( + std::unique_ptr Ctx) + : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit, + std::move(Ctx)) {} +template <> +InstrProfCorrelatorImpl::InstrProfCorrelatorImpl( + std::unique_ptr Ctx) + : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit, + std::move(Ctx)) {} +template <> +bool InstrProfCorrelatorImpl::classof(const InstrProfCorrelator *C) { + return C->getKind() == InstrProfCorrelatorKind::CK_32Bit; +} +template <> +bool InstrProfCorrelatorImpl::classof(const InstrProfCorrelator *C) { + return C->getKind() == InstrProfCorrelatorKind::CK_64Bit; +} + +} // end namespace llvm + +template +llvm::Expected>> +InstrProfCorrelatorImpl::get( + std::unique_ptr Ctx, + const object::ObjectFile &Obj) { + if (Obj.isELF() || Obj.isMachO()) { + auto DICtx = DWARFContext::create(Obj); + return std::make_unique>(std::move(DICtx), + std::move(Ctx)); + } + return make_error(instrprof_error::unsupported_debug_format); +} + +template +Error InstrProfCorrelatorImpl::correlateProfileData() { + assert(Data.empty() && CompressedNames.empty() && Names.empty()); + correlateProfileDataImpl(); + auto Result = + collectPGOFuncNameStrings(Names, /*doCompression=*/true, CompressedNames); + Names.clear(); + return Result; +} + +template +void InstrProfCorrelatorImpl::addProbe(StringRef FunctionName, + uint64_t CFGHash, + IntPtrT CounterOffset, + IntPtrT FunctionPtr, + uint32_t NumCounters) { + Data.push_back({ + maybeSwap(IndexedInstrProf::ComputeHash(FunctionName)), + maybeSwap(CFGHash), + // In this mode, CounterPtr actually stores the section relative address + // of the counter. + maybeSwap(CounterOffset), + maybeSwap(FunctionPtr), + // TODO: Value profiling is not yet supported. + /*ValuesPtr=*/maybeSwap(0), + maybeSwap(NumCounters), + /*NumValueSites=*/{maybeSwap(0), maybeSwap(0)}, + }); + Names.push_back(FunctionName.str()); +} + +template +llvm::Optional +DwarfInstrProfCorrelator::getLocation(const DWARFDie &Die) const { + auto Locations = Die.getLocations(dwarf::DW_AT_location); + if (!Locations) { + consumeError(Locations.takeError()); + return {}; + } + auto &DU = *Die.getDwarfUnit(); + for (auto &Location : *Locations) { + auto AddressSize = DU.getAddressByteSize(); + DataExtractor Data(Location.Expr, DICtx->isLittleEndian(), AddressSize); + DWARFExpression Expr(Data, AddressSize); + for (auto &Op : Expr) + if (Op.getCode() == dwarf::DW_OP_addr) + return Op.getRawOperand(0); + } + return {}; +} + +template +bool DwarfInstrProfCorrelator::isDIEOfProbe(const DWARFDie &Die) { + const auto &ParentDie = Die.getParent(); + if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL()) + return false; + if (Die.getTag() != dwarf::DW_TAG_variable) + return false; + if (!ParentDie.isSubprogramDIE()) + return false; + if (!Die.hasChildren()) + return false; + if (const char *Name = Die.getName(DINameKind::ShortName)) + return StringRef(Name).startswith(getInstrProfCountersVarPrefix()); + return false; +} + +template +void DwarfInstrProfCorrelator::correlateProfileDataImpl() { + auto maybeAddProbe = [&](DWARFDie Die) { + if (!isDIEOfProbe(Die)) + return; + Optional FunctionName; + Optional CFGHash; + Optional CounterPtr = getLocation(Die); + auto FunctionPtr = + dwarf::toAddress(Die.getParent().find(dwarf::DW_AT_low_pc)); + Optional NumCounters; + for (const DWARFDie &Child : Die.children()) { + if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation) + continue; + auto AnnotationFormName = Child.find(dwarf::DW_AT_name); + auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value); + if (!AnnotationFormName || !AnnotationFormValue) + continue; + auto AnnotationNameOrErr = AnnotationFormName->getAsCString(); + if (auto Err = AnnotationNameOrErr.takeError()) { + consumeError(std::move(Err)); + continue; + } + StringRef AnnotationName = *AnnotationNameOrErr; + if (AnnotationName.compare( + InstrProfCorrelator::FunctionNameAttributeName) == 0) { + if (auto EC = + AnnotationFormValue->getAsCString().moveInto(FunctionName)) + consumeError(std::move(EC)); + } else if (AnnotationName.compare( + InstrProfCorrelator::CFGHashAttributeName) == 0) { + CFGHash = AnnotationFormValue->getAsUnsignedConstant(); + } else if (AnnotationName.compare( + InstrProfCorrelator::NumCountersAttributeName) == 0) { + NumCounters = AnnotationFormValue->getAsUnsignedConstant(); + } + } + if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) { + LLVM_DEBUG(dbgs() << "Incomplete DIE for probe\n\tFunctionName: " + << FunctionName << "\n\tCFGHash: " << CFGHash + << "\n\tCounterPtr: " << CounterPtr + << "\n\tNumCounters: " << NumCounters); + LLVM_DEBUG(Die.dump(dbgs())); + return; + } + uint64_t CountersStart = this->Ctx->CountersSectionStart; + uint64_t CountersEnd = this->Ctx->CountersSectionEnd; + if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) { + LLVM_DEBUG( + dbgs() << "CounterPtr out of range for probe\n\tFunction Name: " + << FunctionName << "\n\tExpected: [0x" + << Twine::utohexstr(CountersStart) << ", 0x" + << Twine::utohexstr(CountersEnd) << ")\n\tActual: 0x" + << Twine::utohexstr(*CounterPtr)); + LLVM_DEBUG(Die.dump(dbgs())); + return; + } + if (!FunctionPtr) { + LLVM_DEBUG(dbgs() << "Could not find address of " << *FunctionName + << "\n"); + LLVM_DEBUG(Die.dump(dbgs())); + } + this->addProbe(*FunctionName, *CFGHash, *CounterPtr - CountersStart, + FunctionPtr.getValueOr(0), *NumCounters); + }; + for (auto &CU : DICtx->normal_units()) + for (const auto &Entry : CU->dies()) + maybeAddProbe(DWARFDie(CU.get(), &Entry)); + for (auto &CU : DICtx->dwo_units()) + for (const auto &Entry : CU->dies()) + maybeAddProbe(DWARFDie(CU.get(), &Entry)); +} diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp index 885c1fe49240..37cdf4dd1fe2 100644 --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -52,16 +52,19 @@ static Error initializeReader(InstrProfReader &Reader) { } Expected> -InstrProfReader::create(const Twine &Path) { +InstrProfReader::create(const Twine &Path, + const InstrProfCorrelator *Correlator) { // Set up the buffer to read. auto BufferOrError = setupMemoryBuffer(Path); if (Error E = BufferOrError.takeError()) return std::move(E); - return InstrProfReader::create(std::move(BufferOrError.get())); + return InstrProfReader::create(std::move(BufferOrError.get()), Correlator); } Expected> -InstrProfReader::create(std::unique_ptr Buffer) { +InstrProfReader::create(std::unique_ptr Buffer, + const InstrProfCorrelator *Correlator) { + // Sanity check the buffer. if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits::max()) return make_error(instrprof_error::too_large); @@ -73,9 +76,9 @@ InstrProfReader::create(std::unique_ptr Buffer) { if (IndexedInstrProfReader::hasFormat(*Buffer)) Result.reset(new IndexedInstrProfReader(std::move(Buffer))); else if (RawInstrProfReader64::hasFormat(*Buffer)) - Result.reset(new RawInstrProfReader64(std::move(Buffer))); + Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator)); else if (RawInstrProfReader32::hasFormat(*Buffer)) - Result.reset(new RawInstrProfReader32(std::move(Buffer))); + Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator)); else if (TextInstrProfReader::hasFormat(*Buffer)) Result.reset(new TextInstrProfReader(std::move(Buffer))); else @@ -352,7 +355,7 @@ Error RawInstrProfReader::readNextHeader(const char *CurrentPos) { template Error RawInstrProfReader::createSymtab(InstrProfSymtab &Symtab) { - if (Error E = Symtab.create(StringRef(NamesStart, NamesSize))) + if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart))) return error(std::move(E)); for (const RawInstrProf::ProfileData *I = Data; I != DataEnd; ++I) { const IntPtrT FPtr = swap(I->FunctionPointer); @@ -369,6 +372,10 @@ Error RawInstrProfReader::readHeader( Version = swap(Header.Version); if (GET_VERSION(Version) != RawInstrProf::Version) return error(instrprof_error::unsupported_version); + if (useDebugInfoCorrelate() && !Correlator) + return error(instrprof_error::missing_debug_info_for_correlation); + if (!useDebugInfoCorrelate() && Correlator) + return error(instrprof_error::unexpected_debug_info_for_correlation); BinaryIdsSize = swap(Header.BinaryIdsSize); if (BinaryIdsSize % sizeof(uint64_t)) @@ -380,7 +387,7 @@ Error RawInstrProfReader::readHeader( auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters); auto CountersSize = swap(Header.CountersSize); auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters); - NamesSize = swap(Header.NamesSize); + auto NamesSize = swap(Header.NamesSize); ValueKindLast = swap(Header.ValueKindLast); auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData); @@ -398,15 +405,27 @@ Error RawInstrProfReader::readHeader( if (Start + ValueDataOffset > DataBuffer->getBufferEnd()) return error(instrprof_error::bad_header); - Data = reinterpret_cast *>( - Start + DataOffset); - DataEnd = Data + DataSize; + if (Correlator) { + // These sizes in the raw file are zero because we constructed them in the + // Correlator. + assert(DataSize == 0 && NamesSize == 0); + assert(CountersDelta == 0 && NamesDelta == 0); + Data = Correlator->getDataPointer(); + DataEnd = Data + Correlator->getDataSize(); + NamesStart = Correlator->getCompressedNamesPointer(); + NamesEnd = NamesStart + Correlator->getCompressedNamesSize(); + } else { + Data = reinterpret_cast *>( + Start + DataOffset); + DataEnd = Data + DataSize; + NamesStart = Start + NamesOffset; + NamesEnd = NamesStart + NamesSize; + } // Binary ids start just after the header. BinaryIdsStart = reinterpret_cast(&Header) + sizeof(RawInstrProf::Header); CountersStart = reinterpret_cast(Start + CountersOffset); - NamesStart = Start + NamesOffset; ValueDataStart = reinterpret_cast(Start + ValueDataOffset); const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd(); @@ -440,45 +459,50 @@ Error RawInstrProfReader::readRawCounts( if (NumCounters == 0) return error(instrprof_error::malformed, "number of counters is zero"); - IntPtrT CounterPtr = Data->CounterPtr; - auto *NamesStartAsCounter = reinterpret_cast(NamesStart); - ptrdiff_t MaxNumCounters = NamesStartAsCounter - CountersStart; - - // Check bounds. Note that the counter pointer embedded in the data record - // may itself be corrupt. - if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters) - return error(instrprof_error::malformed, - "counter pointer is out of bounds"); - - // We need to compute the in-buffer counter offset from the in-memory address - // distance. The initial CountersDelta is the in-memory address difference - // start(__llvm_prf_cnts)-start(__llvm_prf_data), so SrcData->CounterPtr - - // CountersDelta computes the offset into the in-buffer counter section. - // - // CountersDelta decreases as we advance to the next data record. - ptrdiff_t CounterOffset = getCounterOffset(CounterPtr); - CountersDelta -= sizeof(*Data); - if (CounterOffset < 0) - return error( - instrprof_error::malformed, - ("counter offset " + Twine(CounterOffset) + " is negative").str()); - - if (CounterOffset > MaxNumCounters) - return error(instrprof_error::malformed, - ("counter offset " + Twine(CounterOffset) + - " is greater than the maximum number of counters " + - Twine((uint32_t)MaxNumCounters)) - .str()); - - if (((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters) - return error(instrprof_error::malformed, - ("number of counters " + - Twine(((uint32_t)CounterOffset + NumCounters)) + - " is greater than the maximum number of counters " + - Twine((uint32_t)MaxNumCounters)) - .str()); - - auto RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters); + ArrayRef RawCounts; + if (Correlator) { + uint64_t CounterOffset = swap(Data->CounterPtr) / sizeof(uint64_t); + RawCounts = + makeArrayRef(CountersStart + CounterOffset, NumCounters); + } else { + IntPtrT CounterPtr = Data->CounterPtr; + ptrdiff_t CounterOffset = getCounterOffset(CounterPtr); + if (CounterOffset < 0) + return error( + instrprof_error::malformed, + ("counter offset " + Twine(CounterOffset) + " is negative").str()); + + // Check bounds. Note that the counter pointer embedded in the data record + // may itself be corrupt. + auto *NamesStartAsCounter = reinterpret_cast(NamesStart); + ptrdiff_t MaxNumCounters = NamesStartAsCounter - CountersStart; + if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters) + return error(instrprof_error::malformed, + "counter pointer is out of bounds"); + // We need to compute the in-buffer counter offset from the in-memory + // address distance. The initial CountersDelta is the in-memory address + // difference start(__llvm_prf_cnts)-start(__llvm_prf_data), so + // SrcData->CounterPtr - CountersDelta computes the offset into the + // in-buffer counter section. + if (CounterOffset > MaxNumCounters) + return error(instrprof_error::malformed, + ("counter offset " + Twine(CounterOffset) + + " is greater than the maximum number of counters " + + Twine((uint32_t)MaxNumCounters)) + .str()); + + if (((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters) + return error(instrprof_error::malformed, + ("number of counters " + + Twine(((uint32_t)CounterOffset + NumCounters)) + + " is greater than the maximum number of counters " + + Twine((uint32_t)MaxNumCounters)) + .str()); + // CountersDelta decreases as we advance to the next data record. + CountersDelta -= sizeof(*Data); + + RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters); + } if (ShouldSwapBytes) { Record.Counts.clear(); @@ -977,11 +1001,10 @@ IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName, if (Err) return std::move(Err); // Found it. Look for counters with the right hash. - for (unsigned I = 0, E = Data.size(); I < E; ++I) { + for (const NamedInstrProfRecord &I : Data) { // Check for a match and fill the vector if there is one. - if (Data[I].Hash == FuncHash) { - return std::move(Data[I]); - } + if (I.Hash == FuncHash) + return std::move(I); } return error(instrprof_error::hash_mismatch); } diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp index 492e3541cb5a..6628eea80640 100644 --- a/llvm/lib/ProfileData/InstrProfWriter.cpp +++ b/llvm/lib/ProfileData/InstrProfWriter.cpp @@ -32,6 +32,7 @@ #include using namespace llvm; +extern cl::opt DebugInfoCorrelate; // A struct to define how the data stream should be patched. For Indexed // profiling, only uint64_t data type is needed. diff --git a/llvm/lib/ProfileData/ProfileSummaryBuilder.cpp b/llvm/lib/ProfileData/ProfileSummaryBuilder.cpp index f54df7b295e3..bbb640cfaee8 100644 --- a/llvm/lib/ProfileData/ProfileSummaryBuilder.cpp +++ b/llvm/lib/ProfileData/ProfileSummaryBuilder.cpp @@ -194,7 +194,7 @@ SampleProfileSummaryBuilder::computeSummaryForProfiles( // more function profiles each with lower counts, which in turn leads to lower // hot thresholds. To compensate for that, by default we merge context // profiles before computing profile summary. - if (UseContextLessSummary || (sampleprof::FunctionSamples::ProfileIsCS && + if (UseContextLessSummary || (sampleprof::FunctionSamples::ProfileIsCSFlat && !UseContextLessSummary.getNumOccurrences())) { for (const auto &I : Profiles) { ContextLessProfiles[I.second.getName()].merge(I.second); diff --git a/llvm/lib/ProfileData/SampleProf.cpp b/llvm/lib/ProfileData/SampleProf.cpp index fd8fd3b675b7..9b01a386a360 100644 --- a/llvm/lib/ProfileData/SampleProf.cpp +++ b/llvm/lib/ProfileData/SampleProf.cpp @@ -35,11 +35,18 @@ static cl::opt ProfileSymbolListCutOff( cl::desc("Cutoff value about how many symbols in profile symbol list " "will be used. This is very useful for performance debugging")); +cl::opt GenerateMergedBaseProfiles( + "generate-merged-base-profiles", cl::init(true), cl::ZeroOrMore, + cl::desc("When generating nested context-sensitive profiles, always " + "generate extra base profile for function with all its context " + "profiles merged into it.")); + namespace llvm { namespace sampleprof { SampleProfileFormat FunctionSamples::Format; bool FunctionSamples::ProfileIsProbeBased = false; -bool FunctionSamples::ProfileIsCS = false; +bool FunctionSamples::ProfileIsCSFlat = false; +bool FunctionSamples::ProfileIsCSNested = false; bool FunctionSamples::UseMD5 = false; bool FunctionSamples::HasUniqSuffix = true; bool FunctionSamples::ProfileIsFS = false; @@ -218,8 +225,9 @@ unsigned FunctionSamples::getOffset(const DILocation *DIL) { 0xffff; } -LineLocation FunctionSamples::getCallSiteIdentifier(const DILocation *DIL) { - if (FunctionSamples::ProfileIsProbeBased) +LineLocation FunctionSamples::getCallSiteIdentifier(const DILocation *DIL, + bool ProfileIsFS) { + if (FunctionSamples::ProfileIsProbeBased) { // In a pseudo-probe based profile, a callsite is simply represented by the // ID of the probe associated with the call instruction. The probe ID is // encoded in the Discriminator field of the call instruction's debug @@ -227,9 +235,19 @@ LineLocation FunctionSamples::getCallSiteIdentifier(const DILocation *DIL) { return LineLocation(PseudoProbeDwarfDiscriminator::extractProbeIndex( DIL->getDiscriminator()), 0); - else - return LineLocation(FunctionSamples::getOffset(DIL), - DIL->getBaseDiscriminator()); + } else { + unsigned Discriminator = + ProfileIsFS ? DIL->getDiscriminator() : DIL->getBaseDiscriminator(); + return LineLocation(FunctionSamples::getOffset(DIL), Discriminator); + } +} + +uint64_t FunctionSamples::getCallSiteHash(StringRef CalleeName, + const LineLocation &Callsite) { + uint64_t NameHash = std::hash{}(CalleeName.str()); + uint64_t LocId = + (((uint64_t)Callsite.LineOffset) << 32) | Callsite.Discriminator; + return NameHash + (LocId << 5) + LocId; } const FunctionSamples *FunctionSamples::findFunctionSamples( @@ -239,21 +257,16 @@ const FunctionSamples *FunctionSamples::findFunctionSamples( const DILocation *PrevDIL = DIL; for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) { - unsigned Discriminator; - if (ProfileIsFS) - Discriminator = DIL->getDiscriminator(); - else - Discriminator = DIL->getBaseDiscriminator(); - // Use C++ linkage name if possible. StringRef Name = PrevDIL->getScope()->getSubprogram()->getLinkageName(); if (Name.empty()) Name = PrevDIL->getScope()->getSubprogram()->getName(); - - S.push_back( - std::make_pair(LineLocation(getOffset(DIL), Discriminator), Name)); + S.emplace_back(FunctionSamples::getCallSiteIdentifier( + DIL, FunctionSamples::ProfileIsFS), + Name); PrevDIL = DIL; } + if (S.size() == 0) return this; const FunctionSamples *FS = this; @@ -454,3 +467,81 @@ void ProfileSymbolList::dump(raw_ostream &OS) const { for (auto &Sym : SortedList) OS << Sym << "\n"; } + +CSProfileConverter::FrameNode * +CSProfileConverter::FrameNode::getOrCreateChildFrame( + const LineLocation &CallSite, StringRef CalleeName) { + uint64_t Hash = FunctionSamples::getCallSiteHash(CalleeName, CallSite); + auto It = AllChildFrames.find(Hash); + if (It != AllChildFrames.end()) { + assert(It->second.FuncName == CalleeName && + "Hash collision for child context node"); + return &It->second; + } + + AllChildFrames[Hash] = FrameNode(CalleeName, nullptr, CallSite); + return &AllChildFrames[Hash]; +} + +CSProfileConverter::CSProfileConverter(SampleProfileMap &Profiles) + : ProfileMap(Profiles) { + for (auto &FuncSample : Profiles) { + FunctionSamples *FSamples = &FuncSample.second; + auto *NewNode = getOrCreateContextPath(FSamples->getContext()); + assert(!NewNode->FuncSamples && "New node cannot have sample profile"); + NewNode->FuncSamples = FSamples; + } +} + +CSProfileConverter::FrameNode * +CSProfileConverter::getOrCreateContextPath(const SampleContext &Context) { + auto Node = &RootFrame; + LineLocation CallSiteLoc(0, 0); + for (auto &Callsite : Context.getContextFrames()) { + Node = Node->getOrCreateChildFrame(CallSiteLoc, Callsite.FuncName); + CallSiteLoc = Callsite.Location; + } + return Node; +} + +void CSProfileConverter::convertProfiles(CSProfileConverter::FrameNode &Node) { + // Process each child profile. Add each child profile to callsite profile map + // of the current node `Node` if `Node` comes with a profile. Otherwise + // promote the child profile to a standalone profile. + auto *NodeProfile = Node.FuncSamples; + for (auto &It : Node.AllChildFrames) { + auto &ChildNode = It.second; + convertProfiles(ChildNode); + auto *ChildProfile = ChildNode.FuncSamples; + if (!ChildProfile) + continue; + SampleContext OrigChildContext = ChildProfile->getContext(); + // Reset the child context to be contextless. + ChildProfile->getContext().setName(OrigChildContext.getName()); + if (NodeProfile) { + // Add child profile to the callsite profile map. + auto &SamplesMap = NodeProfile->functionSamplesAt(ChildNode.CallSiteLoc); + SamplesMap.emplace(OrigChildContext.getName().str(), *ChildProfile); + NodeProfile->addTotalSamples(ChildProfile->getTotalSamples()); + } + + // Separate child profile to be a standalone profile, if the current parent + // profile doesn't exist. This is a duplicating operation when the child + // profile is already incorporated into the parent which is still useful and + // thus done optionally. It is seen that duplicating context profiles into + // base profiles improves the code quality for thinlto build by allowing a + // profile in the prelink phase for to-be-fully-inlined functions. + if (!NodeProfile || GenerateMergedBaseProfiles) + ProfileMap[ChildProfile->getContext()].merge(*ChildProfile); + + // Contexts coming with a `ContextShouldBeInlined` attribute indicate this + // is a preinliner-computed profile. + if (OrigChildContext.hasAttribute(ContextShouldBeInlined)) + FunctionSamples::ProfileIsCSNested = true; + + // Remove the original child profile. + ProfileMap.erase(OrigChildContext); + } +} + +void CSProfileConverter::convertProfiles() { convertProfiles(RootFrame); } diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp index eefb7c2ba627..da16309fb82c 100644 --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -146,7 +146,7 @@ static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth, if (Depth == 0) return false; - if (Depth == 1 && Input[Depth] == '!') { + if (Input[Depth] == '!') { LineTy = LineType::Metadata; return parseMetadata(Input.substr(Depth), FunctionHash, Attributes); } @@ -244,11 +244,11 @@ std::error_code SampleProfileReaderText::readImpl() { sampleprof_error Result = sampleprof_error::success; InlineCallStack InlineStack; - uint32_t ProbeProfileCount = 0; + uint32_t TopLevelProbeProfileCount = 0; - // SeenMetadata tracks whether we have processed metadata for the current - // top-level function profile. - bool SeenMetadata = false; + // DepthMetadata tracks whether we have processed metadata for the current + // top-level or nested function profile. + uint32_t DepthMetadata = 0; ProfileIsFS = ProfileIsFSDisciminator; FunctionSamples::ProfileIsFS = ProfileIsFS; @@ -275,7 +275,7 @@ std::error_code SampleProfileReaderText::readImpl() { "Expected 'mangled_name:NUM:NUM', found " + *LineIt); return sampleprof_error::malformed; } - SeenMetadata = false; + DepthMetadata = 0; SampleContext FContext(FName, CSNameTable); if (FContext.hasContext()) ++CSProfileCount; @@ -302,7 +302,7 @@ std::error_code SampleProfileReaderText::readImpl() { *LineIt); return sampleprof_error::malformed; } - if (SeenMetadata && LineTy != LineType::Metadata) { + if (LineTy != LineType::Metadata && Depth == DepthMetadata) { // Metadata must be put at the end of a function profile. reportError(LineIt.line_number(), "Found non-metadata after metadata: " + *LineIt); @@ -322,6 +322,7 @@ std::error_code SampleProfileReaderText::readImpl() { FSamples.setName(FName); MergeResult(Result, FSamples.addTotalSamples(NumSamples)); InlineStack.push_back(&FSamples); + DepthMetadata = 0; break; } case LineType::BodyProfile: { @@ -342,11 +343,13 @@ std::error_code SampleProfileReaderText::readImpl() { FunctionSamples &FProfile = *InlineStack.back(); if (FunctionHash) { FProfile.setFunctionHash(FunctionHash); - ++ProbeProfileCount; + if (Depth == 1) + ++TopLevelProbeProfileCount; } - if (Attributes) - FProfile.getContext().setAllAttributes(Attributes); - SeenMetadata = true; + FProfile.getContext().setAllAttributes(Attributes); + if (Attributes & (uint32_t)ContextShouldBeInlined) + ProfileIsCSNested = true; + DepthMetadata = Depth; break; } } @@ -355,12 +358,14 @@ std::error_code SampleProfileReaderText::readImpl() { assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) && "Cannot have both context-sensitive and regular profile"); - ProfileIsCS = (CSProfileCount > 0); - assert((ProbeProfileCount == 0 || ProbeProfileCount == Profiles.size()) && + ProfileIsCSFlat = (CSProfileCount > 0); + assert((TopLevelProbeProfileCount == 0 || + TopLevelProbeProfileCount == Profiles.size()) && "Cannot have both probe-based profiles and regular profiles"); - ProfileIsProbeBased = (ProbeProfileCount > 0); + ProfileIsProbeBased = (TopLevelProbeProfileCount > 0); FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased; - FunctionSamples::ProfileIsCS = ProfileIsCS; + FunctionSamples::ProfileIsCSFlat = ProfileIsCSFlat; + FunctionSamples::ProfileIsCSNested = ProfileIsCSNested; if (Result == sampleprof_error::success) computeSummary(); @@ -625,7 +630,7 @@ SampleProfileReaderExtBinaryBase::readContextFromTable() { ErrorOr SampleProfileReaderExtBinaryBase::readSampleContextFromTable() { - if (ProfileIsCS) { + if (ProfileIsCSFlat) { auto FContext(readContextFromTable()); if (std::error_code EC = FContext.getError()) return EC; @@ -649,7 +654,7 @@ std::error_code SampleProfileReaderExtBinaryBase::readOneSection( if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial)) Summary->setPartialProfile(true); if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFullContext)) - FunctionSamples::ProfileIsCS = ProfileIsCS = true; + FunctionSamples::ProfileIsCSFlat = ProfileIsCSFlat = true; if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator)) FunctionSamples::ProfileIsFS = ProfileIsFS = true; break; @@ -683,6 +688,9 @@ std::error_code SampleProfileReaderExtBinaryBase::readOneSection( ProfileIsProbeBased = hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased); FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased; + ProfileIsCSNested = + hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsCSNested); + FunctionSamples::ProfileIsCSNested = ProfileIsCSNested; bool HasAttribute = hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute); if (std::error_code EC = readFuncMetadata(HasAttribute)) @@ -770,7 +778,7 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() { } } - if (ProfileIsCS) { + if (ProfileIsCSFlat) { DenseSet FuncGuidsToUse; if (useMD5()) { for (auto Name : FuncsToUse) @@ -840,7 +848,7 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() { } assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) && "Cannot have both context-sensitive and regular profile"); - assert((!CSProfileCount || ProfileIsCS) && + assert((!CSProfileCount || ProfileIsCSFlat) && "Section flag should be consistent with actual profile"); return sampleprof_error::success; } @@ -1078,30 +1086,77 @@ std::error_code SampleProfileReaderExtBinaryBase::readCSNameTableSec() { } std::error_code -SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute) { - while (Data < End) { - auto FContext(readSampleContextFromTable()); - if (std::error_code EC = FContext.getError()) - return EC; - bool ProfileInMap = Profiles.count(*FContext); +SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute, + FunctionSamples *FProfile) { + if (Data < End) { if (ProfileIsProbeBased) { auto Checksum = readNumber(); if (std::error_code EC = Checksum.getError()) return EC; - if (ProfileInMap) - Profiles[*FContext].setFunctionHash(*Checksum); + if (FProfile) + FProfile->setFunctionHash(*Checksum); } if (ProfileHasAttribute) { auto Attributes = readNumber(); if (std::error_code EC = Attributes.getError()) return EC; - if (ProfileInMap) - Profiles[*FContext].getContext().setAllAttributes(*Attributes); + if (FProfile) + FProfile->getContext().setAllAttributes(*Attributes); + } + + if (!ProfileIsCSFlat) { + // Read all the attributes for inlined function calls. + auto NumCallsites = readNumber(); + if (std::error_code EC = NumCallsites.getError()) + return EC; + + for (uint32_t J = 0; J < *NumCallsites; ++J) { + auto LineOffset = readNumber(); + if (std::error_code EC = LineOffset.getError()) + return EC; + + auto Discriminator = readNumber(); + if (std::error_code EC = Discriminator.getError()) + return EC; + + auto FContext(readSampleContextFromTable()); + if (std::error_code EC = FContext.getError()) + return EC; + + FunctionSamples *CalleeProfile = nullptr; + if (FProfile) { + CalleeProfile = const_cast( + &FProfile->functionSamplesAt(LineLocation( + *LineOffset, + *Discriminator))[std::string(FContext.get().getName())]); + } + if (std::error_code EC = + readFuncMetadata(ProfileHasAttribute, CalleeProfile)) + return EC; + } } } + return sampleprof_error::success; +} + +std::error_code +SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute) { + while (Data < End) { + auto FContext(readSampleContextFromTable()); + if (std::error_code EC = FContext.getError()) + return EC; + FunctionSamples *FProfile = nullptr; + auto It = Profiles.find(*FContext); + if (It != Profiles.end()) + FProfile = &It->second; + + if (std::error_code EC = readFuncMetadata(ProfileHasAttribute, FProfile)) + return EC; + } + assert(Data == End && "More data is read than expected"); return sampleprof_error::success; } @@ -1233,6 +1288,8 @@ static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) { Flags.append("probe,"); if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute)) Flags.append("attr,"); + if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsCSNested)) + Flags.append("preinlined,"); break; default: break; diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp index 78006aab1541..6f02bd203a9f 100644 --- a/llvm/lib/ProfileData/SampleProfWriter.cpp +++ b/llvm/lib/ProfileData/SampleProfWriter.cpp @@ -172,7 +172,7 @@ std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() { return (std::error_code)sampleprof_error::success; }; - if (FunctionSamples::ProfileIsCS) { + if (FunctionSamples::ProfileIsCSFlat) { // Sort the contexts before writing them out. This is to help fast load all // context profiles for a function as well as their callee contexts which // can help profile-guided importing for ThinLTO. @@ -194,18 +194,46 @@ std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() { return sampleprof_error::success; } +std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata( + const FunctionSamples &FunctionProfile) { + auto &OS = *OutputStream; + if (std::error_code EC = writeContextIdx(FunctionProfile.getContext())) + return EC; + + if (FunctionSamples::ProfileIsProbeBased) + encodeULEB128(FunctionProfile.getFunctionHash(), OS); + if (FunctionSamples::ProfileIsCSFlat || FunctionSamples::ProfileIsCSNested) { + encodeULEB128(FunctionProfile.getContext().getAllAttributes(), OS); + } + + if (!FunctionSamples::ProfileIsCSFlat) { + // Recursively emit attributes for all callee samples. + uint64_t NumCallsites = 0; + for (const auto &J : FunctionProfile.getCallsiteSamples()) + NumCallsites += J.second.size(); + encodeULEB128(NumCallsites, OS); + for (const auto &J : FunctionProfile.getCallsiteSamples()) { + for (const auto &FS : J.second) { + LineLocation Loc = J.first; + encodeULEB128(Loc.LineOffset, OS); + encodeULEB128(Loc.Discriminator, OS); + if (std::error_code EC = writeFuncMetadata(FS.second)) + return EC; + } + } + } + + return sampleprof_error::success; +} + std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata( const SampleProfileMap &Profiles) { - if (!FunctionSamples::ProfileIsProbeBased && !FunctionSamples::ProfileIsCS) + if (!FunctionSamples::ProfileIsProbeBased && + !FunctionSamples::ProfileIsCSFlat && !FunctionSamples::ProfileIsCSNested) return sampleprof_error::success; - auto &OS = *OutputStream; for (const auto &Entry : Profiles) { - if (std::error_code EC = writeContextIdx(Entry.second.getContext())) + if (std::error_code EC = writeFuncMetadata(Entry.second)) return EC; - if (FunctionSamples::ProfileIsProbeBased) - encodeULEB128(Entry.second.getFunctionHash(), OS); - if (FunctionSamples::ProfileIsCS) - encodeULEB128(Entry.second.getContext().getAllAttributes(), OS); } return sampleprof_error::success; } @@ -295,10 +323,13 @@ std::error_code SampleProfileWriterExtBinaryBase::writeOneSection( setToCompressSection(SecProfileSymbolList); if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased) addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased); - if (Type == SecProfSummary && FunctionSamples::ProfileIsCS) - addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext); - if (Type == SecFuncMetadata && FunctionSamples::ProfileIsCS) + if (Type == SecFuncMetadata && FunctionSamples::ProfileIsCSNested) + addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsCSNested); + if (Type == SecFuncMetadata && + (FunctionSamples::ProfileIsCSFlat || FunctionSamples::ProfileIsCSNested)) addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute); + if (Type == SecProfSummary && FunctionSamples::ProfileIsCSFlat) + addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext); if (Type == SecProfSummary && FunctionSamples::ProfileIsFS) addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator); @@ -440,7 +471,7 @@ SampleProfileWriterCompactBinary::write(const SampleProfileMap &ProfileMap) { /// it needs to be parsed by the SampleProfileReaderText class. std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { auto &OS = *OutputStream; - if (FunctionSamples::ProfileIsCS) + if (FunctionSamples::ProfileIsCSFlat) OS << "[" << S.getContext().toString() << "]:" << S.getTotalSamples(); else OS << S.getName() << ":" << S.getTotalSamples(); @@ -483,15 +514,14 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { } Indent -= 1; - if (Indent == 0) { - if (FunctionSamples::ProfileIsProbeBased) { - OS.indent(Indent + 1); - OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; - } - if (FunctionSamples::ProfileIsCS) { - OS.indent(Indent + 1); - OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n"; - } + if (FunctionSamples::ProfileIsProbeBased) { + OS.indent(Indent + 1); + OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; + } + + if (S.getContext().getAllAttributes()) { + OS.indent(Indent + 1); + OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n"; } return sampleprof_error::success; @@ -841,7 +871,8 @@ SampleProfileWriter::create(std::unique_ptr &OS, std::unique_ptr Writer; // Currently only Text and Extended Binary format are supported for CSSPGO. - if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) && + if ((FunctionSamples::ProfileIsCSFlat || + FunctionSamples::ProfileIsProbeBased) && (Format == SPF_Binary || Format == SPF_Compact_Binary)) return sampleprof_error::unsupported_writing_format; diff --git a/llvm/lib/Support/AArch64TargetParser.cpp b/llvm/lib/Support/AArch64TargetParser.cpp index a3e41ccd199c..4bc9c8487131 100644 --- a/llvm/lib/Support/AArch64TargetParser.cpp +++ b/llvm/lib/Support/AArch64TargetParser.cpp @@ -240,4 +240,4 @@ AArch64::ArchKind AArch64::parseCPUArch(StringRef CPU) { return C.ArchID; } return ArchKind::INVALID; -} \ No newline at end of file +} diff --git a/llvm/lib/Support/Caching.cpp b/llvm/lib/Support/Caching.cpp index a2fe37a26617..8c685640f791 100644 --- a/llvm/lib/Support/Caching.cpp +++ b/llvm/lib/Support/Caching.cpp @@ -79,14 +79,13 @@ Expected llvm::localCache(Twine CacheNameRef, struct CacheStream : CachedFileStream { AddBufferFn AddBuffer; sys::fs::TempFile TempFile; - std::string EntryPath; unsigned Task; CacheStream(std::unique_ptr OS, AddBufferFn AddBuffer, sys::fs::TempFile TempFile, std::string EntryPath, unsigned Task) - : CachedFileStream(std::move(OS)), AddBuffer(std::move(AddBuffer)), - TempFile(std::move(TempFile)), EntryPath(std::move(EntryPath)), + : CachedFileStream(std::move(OS), std::move(EntryPath)), + AddBuffer(std::move(AddBuffer)), TempFile(std::move(TempFile)), Task(Task) {} ~CacheStream() { @@ -99,7 +98,7 @@ Expected llvm::localCache(Twine CacheNameRef, // Open the file first to avoid racing with a cache pruner. ErrorOr> MBOrErr = MemoryBuffer::getOpenFile( - sys::fs::convertFDToNativeFile(TempFile.FD), TempFile.TmpName, + sys::fs::convertFDToNativeFile(TempFile.FD), ObjectPathName, /*FileSize=*/-1, /*RequiresNullTerminator=*/false); if (!MBOrErr) report_fatal_error(Twine("Failed to open new cache file ") + @@ -115,14 +114,14 @@ Expected llvm::localCache(Twine CacheNameRef, // AddBuffer a copy of the bytes we wrote in that case. We do this // instead of just using the existing file, because the pruner might // delete the file before we get a chance to use it. - Error E = TempFile.keep(EntryPath); + Error E = TempFile.keep(ObjectPathName); E = handleErrors(std::move(E), [&](const ECError &E) -> Error { std::error_code EC = E.convertToErrorCode(); if (EC != errc::permission_denied) return errorCodeToError(EC); auto MBCopy = MemoryBuffer::getMemBufferCopy((*MBOrErr)->getBuffer(), - EntryPath); + ObjectPathName); MBOrErr = std::move(MBCopy); // FIXME: should we consume the discard error? @@ -133,7 +132,7 @@ Expected llvm::localCache(Twine CacheNameRef, if (E) report_fatal_error(Twine("Failed to rename temporary file ") + - TempFile.TmpName + " to " + EntryPath + ": " + + TempFile.TmpName + " to " + ObjectPathName + ": " + toString(std::move(E)) + "\n"); AddBuffer(Task, std::move(*MBOrErr)); diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 5b7004c86f5a..4153a69abf5d 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -1538,10 +1538,8 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, ErrorParsing = true; } else { - for (SmallVectorImpl